235 lines
7.9 KiB
C++
235 lines
7.9 KiB
C++
/**
|
|
* @file ProductionOrder.cpp
|
|
* @author The ARTIS Development Team
|
|
* See the AUTHORS or Authors.txt file
|
|
*/
|
|
|
|
/*
|
|
* ARTIS - the multimodeling and simulation environment
|
|
* This file is a part of the ARTIS environment
|
|
*
|
|
* Copyright (C) 2013-2023 ULCO http://www.univ-littoral.fr
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "ProductionOrder.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <memory>
|
|
|
|
namespace artis::factory {
|
|
|
|
void put_bits(uint8_t *buffer, ProductionOrder::Reference &reference, uint8_t data, uint8_t bit_number) {
|
|
if (8 - reference._bit_index >= bit_number) {
|
|
buffer[reference._byte_index] |= data << (8 - bit_number - reference._bit_index);
|
|
reference._bit_index += bit_number;
|
|
if (reference._bit_index == 8) {
|
|
++reference._byte_index;
|
|
reference._bit_index = 0;
|
|
}
|
|
} else {
|
|
buffer[reference._byte_index] |= data >> (bit_number - (8 - reference._bit_index));
|
|
++reference._byte_index;
|
|
reference._bit_index = bit_number - (8 - reference._bit_index);
|
|
data &= 0xFF >> (8 - reference._bit_index);
|
|
buffer[reference._byte_index] |= data << (8 - reference._bit_index);
|
|
}
|
|
}
|
|
|
|
uint8_t get_bits(uint8_t const *buffer,
|
|
const ProductionOrder::Reference &reference,
|
|
uint8_t bit_number) {
|
|
uint8_t data = 0;
|
|
|
|
if (8 - reference._bit_index >= bit_number) {
|
|
data = (uint8_t) (buffer[reference._byte_index] << reference._bit_index) >>
|
|
(8 - bit_number);
|
|
} else {
|
|
uint8_t mask = ~(uint8_t) (0xFF << (8 - reference._bit_index));
|
|
|
|
data = (uint8_t) (buffer[reference._byte_index] & mask);
|
|
data <<= bit_number - (8 - reference._bit_index);
|
|
data |= (uint8_t) (buffer[reference._byte_index + 1] >>
|
|
(8 - (bit_number - (8 - reference._bit_index))));
|
|
}
|
|
return data;
|
|
}
|
|
|
|
void ProductionOrder::Reference::operator+=(uint8_t p) {
|
|
_byte_index += (_bit_index + p) / 8;
|
|
_bit_index += p;
|
|
_bit_index %= 8;
|
|
}
|
|
|
|
ProductionOrder::ProductionOrder(uint8_t *buffer, std::size_t size)
|
|
: _buffer(nullptr), _size(size), _bsize(0), _current_operation(nullptr) {
|
|
_buffer = new uint8_t[size];
|
|
std::memcpy(_buffer, buffer, size);
|
|
_bsize = (_buffer[BIT_NUMBER_POSITION] << 8) + _buffer[BIT_NUMBER_POSITION + 1];
|
|
update_operation(_buffer[INDEX_POSITION]);
|
|
_is_finish = _buffer[INDEX_POSITION] + 1 >= _buffer[OPERATION_NUMBER_POSITION];
|
|
}
|
|
|
|
ProductionOrder::ProductionOrder(uint16_t ID, uint16_t parent_ID, uint32_t due_date, uint16_t product_ID,
|
|
const Program &program) : _is_finish(false) {
|
|
Reference reference{0, 0};
|
|
std::size_t operation_number = 0;
|
|
|
|
_bsize = HEADER_SIZE * 8; // size + index + operation number
|
|
std::for_each(program.cbegin(), program.cend(),
|
|
[this, &operation_number](const PoolMachineSequence &sequence) {
|
|
_bsize +=
|
|
sequence._machines.size() * (MACHINE_SIZE + TYPE_SIZE);
|
|
_bsize += POOL_SIZE + TYPE_SIZE;
|
|
operation_number += sequence._machines.size() + 1;
|
|
});
|
|
_size = _bsize / 8 + 1;
|
|
_buffer = new uint8_t[_size];
|
|
memset(_buffer, 0, _size);
|
|
|
|
// bit number
|
|
_buffer[reference._byte_index++] = (uint8_t) (_bsize >> 8);
|
|
_buffer[reference._byte_index++] = (uint8_t) (_bsize & 0xFF);
|
|
|
|
// ID
|
|
_buffer[reference._byte_index++] = (uint8_t) (ID >> 8);
|
|
_buffer[reference._byte_index++] = (uint8_t) (ID & 0xFF);
|
|
|
|
// parent ID
|
|
_buffer[reference._byte_index++] = (uint8_t) (parent_ID >> 8);
|
|
_buffer[reference._byte_index++] = (uint8_t) (parent_ID & 0xFF);
|
|
|
|
// due date
|
|
_buffer[reference._byte_index++] = (uint8_t) (due_date >> 24);
|
|
_buffer[reference._byte_index++] = (uint8_t) ((due_date >> 16) & 0xFF);
|
|
_buffer[reference._byte_index++] = (uint8_t) ((due_date >> 8) & 0xFF);
|
|
_buffer[reference._byte_index++] = (uint8_t) (due_date & 0xFF);
|
|
|
|
// product ID
|
|
_buffer[reference._byte_index++] = (uint8_t) (product_ID >> 8);
|
|
_buffer[reference._byte_index++] = (uint8_t) (product_ID & 0xFF);
|
|
|
|
// index
|
|
_buffer[reference._byte_index++] = (uint8_t) (0);
|
|
|
|
assert(operation_number < 256);
|
|
|
|
// operation number
|
|
_buffer[reference._byte_index++] = (int8_t) (operation_number);
|
|
|
|
// operations {change pool ; N change machine} * M
|
|
std::for_each(program.cbegin(), program.cend(), [this, &reference](const PoolMachineSequence &sequence) {
|
|
const ChangePool &operation = sequence._pool;
|
|
|
|
assert(operation._pool_id < (1 << POOL_SIZE));
|
|
|
|
put_bits(_buffer, reference, CHANGE_POOL_TYPE, TYPE_SIZE);
|
|
put_bits(_buffer, reference, operation._pool_id, POOL_SIZE);
|
|
std::for_each(sequence._machines.cbegin(), sequence._machines.cend(),
|
|
[this, &reference](const ChangeMachine &operation) {
|
|
assert(operation._machine_id < (1 << MACHINE_SIZE));
|
|
|
|
put_bits(_buffer, reference, CHANGE_MACHINE_TYPE, TYPE_SIZE);
|
|
put_bits(_buffer, reference, operation._machine_id, MACHINE_SIZE);
|
|
});
|
|
});
|
|
|
|
// current operation
|
|
_current_operation = std::make_unique<ChangePool>(program.begin()->_pool);
|
|
}
|
|
|
|
std::unique_ptr<Operation> ProductionOrder::get_operation(uint8_t index) const {
|
|
Reference reference{HEADER_SIZE, 0};
|
|
uint8_t operation_type = get_bits(_buffer, reference, TYPE_SIZE);
|
|
|
|
reference += TYPE_SIZE;
|
|
while (index > 0) {
|
|
switch (operation_type) {
|
|
case CHANGE_POOL_TYPE: {
|
|
reference += POOL_SIZE;
|
|
break;
|
|
}
|
|
case CHANGE_MACHINE_TYPE: {
|
|
reference += MACHINE_SIZE;
|
|
break;
|
|
}
|
|
default:
|
|
assert(false);
|
|
}
|
|
operation_type = get_bits(_buffer, reference, TYPE_SIZE);
|
|
reference += TYPE_SIZE;
|
|
--index;
|
|
}
|
|
switch (operation_type) {
|
|
case CHANGE_POOL_TYPE: {
|
|
return std::make_unique<ChangePool>(get_bits(_buffer, reference, POOL_SIZE));
|
|
}
|
|
case CHANGE_MACHINE_TYPE: {
|
|
return std::make_unique<ChangeMachine>(get_bits(_buffer, reference, MACHINE_SIZE));
|
|
}
|
|
}
|
|
assert(false);
|
|
return {};
|
|
}
|
|
|
|
std::unique_ptr<Operation> ProductionOrder::last_operation() const {
|
|
return get_operation(operation_number() - 1);
|
|
}
|
|
|
|
void ProductionOrder::update_operation(uint8_t index) {
|
|
_current_operation = get_operation(index);
|
|
}
|
|
|
|
void ProductionOrder::next() {
|
|
if (_buffer[INDEX_POSITION] + 1 < _buffer[OPERATION_NUMBER_POSITION]) {
|
|
update_operation(++_buffer[INDEX_POSITION]);
|
|
} else {
|
|
_current_operation.reset(nullptr);
|
|
_is_finish = true;
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<Operation> ProductionOrder::previous_operation() const {
|
|
return get_operation(_buffer[INDEX_POSITION] - 1);
|
|
}
|
|
|
|
std::string ProductionOrder::to_string() const {
|
|
std::string str = "[ ";
|
|
uint16_t ID = (_buffer[ID_POSITION] << 8) + _buffer[ID_POSITION + 1];
|
|
uint16_t parentID = (_buffer[PARENT_ID_POSITION] << 8) + _buffer[PARENT_ID_POSITION + 1];
|
|
|
|
str += std::to_string(ID);
|
|
if (ID != parentID) {
|
|
str += + "/" + std::to_string(parentID) +" ][ ";
|
|
|
|
}
|
|
str += " ][ ";
|
|
for (uint8_t i = 0; i < _buffer[OPERATION_NUMBER_POSITION]; ++i) {
|
|
if (_buffer[INDEX_POSITION] == i) {
|
|
str += "<";
|
|
}
|
|
str += get_operation(i)->to_string();
|
|
if (_buffer[INDEX_POSITION] == i) {
|
|
str += ">";
|
|
}
|
|
str += " ";
|
|
}
|
|
str += "]";
|
|
return str;
|
|
}
|
|
|
|
} // namespace artis::factory
|