#ifndef SDP_SCHEDULER_UTILS_H
#define SDP_SCHEDULER_UTILS_H
// Все зоны линии
enum Zones {
ZONE_LOAD_1 = 0, // загрузка 0, используется как точка появления барабанов
ZONE_LOAD_2, // загрузка 1, используется как конечная точка барабанов
ZONE_DEGREASING, // обезжиривание
ZONE_WASHING_1A, // промывка 1А
ZONE_WASHING_1B, // промывка 1Б
ZONE_ETCHING_1, // травление 1
ZONE_ETCHING_2, // травление 2
ZONE_WASHING_2A, // промывка 2А
ZONE_WASHING_2B, // промывка 2Б
ZONE_GALVANIZING_1, // цинкование 1
ZONE_GALVANIZING_2, // цинкование 2
ZONE_GALVANIZING_3, // цинкование 3
ZONE_GALVANIZING_4, // цинкование 4
ZONE_GALVANIZING_5, // цинкование 5
ZONE_GALVANIZING_6, // цинкование 6
ZONE_GALVANIZING_7, // цинкование 7
ZONE_GALVANIZING_8, // цинкование 8
ZONE_WASHING_3A, // промывка 3А
ZONE_WASHING_3B, // промывка 3Б
ZONE_PASSIVATION, // пассивация
ZONE_WASHING_4A, // промывка 4A
ZONE_WASHING_4B, // промывка 4Б
ZONE_UNLOAD, // зона выгрузки
};
#define BARRELS_COUNT 10
union barrel_flags {
short raw_word;
struct {
char is_exist: 1;
char is_up: 1; // для панели
char robot: 2; // обслуживающий робот
char is_night: 1; // ночной барабан, имеет такой статус если он в промывке в ночном режиме или в промывке,
// но пока не дождался очереди на выход из ночного режима
char is_empty: 1; // пустой барабан, нужен для работы операции возврата
};
};
struct barrel {
union barrel_flags flags;
short zone;
// программный таймер, тикает сразу у всех барабанов,
short software_timer;
// время процессов
short time_degreasing; // Время обезжиривания
short time_washing_1a; // Время промывки 1А
short time_washing_1b; // Время промывки 1Б
short time_etching; // Время травления
short time_washing_2a; // Время промывки 2А
short time_washing_2b; // Время промывки 2Б
short time_galvanizing; // Время цинкования
short time_washing_3a; // Время промывки 3А
short time_washing_3b; // Время промывки 3Б
short time_passivation; // Время пассивации
short time_washing_4a; // Время промывки 4А
short time_washing_4b; // Время промывки 4Б
};
union robot_regs_mx {
short raw_word;
struct {
char correct_status: 1;
char last_cmd_executed: 1;
char correct_sensor: 1;
char move_to_zone: 1;
char move_to_offset: 1;
char move_to_precise: 1;
char do_correct: 1;
char do_parking: 1;
char hla_left: 1;
char hla_right: 1;
char auto_mode: 1;
char error: 1;
};
};
union robot_regs_dx {
short raw_data[6];
struct {
short current_zone;
short target_zone;
short left_max;
short right_max;
short output_current;
short output_freq;
};
};
union robot_regs_mz {
short raw_word;
struct {
char correct_status: 1;
char last_cmd_executed: 1;
char is_up: 1;
char move_up: 1;
char move_down: 1;
char do_correct: 1;
char hla_up: 1;
char hla_down: 1;
char auto_mode: 1;
char error: 1;
};
};
union robot_regs_dz {
short raw_data[3];
struct {
short current_zone;
short output_current;
short output_freq;
};
};
struct robot_regs {
union robot_regs_mx mx;
union robot_regs_dx dx;
union robot_regs_mz mz;
union robot_regs_dz dz;
};
// NOTE первой командой на любую транзакцию должна стоять команда опустить траверсу (в 22 зоне по идее никогда не закончим)
struct robot_code {
short barrel_id; // если требуются операции с барабаном, то для корректного исполнения нужно указать значение >= 0
short PC; // когда -1, код не выполняется
unsigned short code[16]; // формат кода: [команды] <команда 0>
};
#ifdef __cplusplus
extern "C" {
#endif
#ifdef EMULATOR
extern struct barrel barrels[BARRELS_COUNT];
extern struct robot_regs robot1;
extern struct robot_regs robot2;
extern struct robot_code robot1_code;
extern struct robot_code robot2_code;
// времена для барабанов, нужно копировать их только при создании барабанов
extern short hla_time_degreasing;
extern short hla_time_washing_1a;
extern short hla_time_washing_1b;
extern short hla_time_etching;
extern short hla_time_washing_2a;
extern short hla_time_washing_2b;
extern short hla_time_galvanizing;
extern short hla_time_washing_3a;
extern short hla_time_washing_3b;
extern short hla_time_passivation;
extern short hla_time_washing_4a;
extern short hla_time_washing_4b;
// времена скапывания, одинаковые для всех барабанов
extern short hla_time_digging;
extern short hla_time_reagent;
extern short hla_time_washing_1;
extern short hla_time_washing_2;
// выбор зоны промежуточной с панели
extern short hla_exchange_zone;
// выбор отключенных зон
extern short hla_disabled_zones;
extern char hla_robot1_en;
extern char hla_robot2_en;
// пауза для автоматического режима, при паузе идут таймера, но команды не могут быть выданы
extern char auto_mode_pause;
// Кнопки с панели
extern char hla_night_mode;
extern char hla_correct_command;
extern char hla_zinc_again;
// разрешение на работу планировщика
extern char scheduler_en;
// сигнал инициализации планировщика, должен быть установлен по фронту разрешения на работу
extern char scheduler_start_signal;
extern short scheduler_stage;
#else
#define barrels ((struct barrel*)barrels_array)
#define robot1 (*((struct robot_regs*)&robot1_reg_mx))
#define robot2 (*((struct robot_regs*)&robot2_reg_mx))
#define robot1_code (*((struct robot_code*)_robot1_code_struct))
#define robot2_code (*((struct robot_code*)_robot2_code_struct))
// времена для барабанов, нужно копировать их только при создании барабанов
#define hla_time_degreasing _c_hla_time_degreasing
#define hla_time_washing_1a _c_hla_time_washing_1a
#define hla_time_washing_1b _c_hla_time_washing_1b
#define hla_time_etching _c_hla_time_etching
#define hla_time_washing_2a _c_hla_time_washing_2a
#define hla_time_washing_2b _c_hla_time_washing_2b
#define hla_time_galvanizing _c_hla_time_galvanizing
#define hla_time_washing_3a _c_hla_time_washing_3a
#define hla_time_washing_3b _c_hla_time_washing_3b
#define hla_time_passivation _c_hla_time_passivation
#define hla_time_washing_4a _c_hla_time_washing_4a
#define hla_time_washing_4b _c_hla_time_washing_4b
// времена скапывания, одинаковые для всех барабанов
#define hla_time_digging _c_hla_time_digging
#define hla_time_reagent _c_hla_time_reagent
#define hla_time_washing_1 _c_hla_time_washing_1
#define hla_time_washing_2 _c_hla_time_washing_2
#define hla_exchange_zone _c_hla_exchange_zone
#define hla_disabled_zones _c_hla_disabled_zones
#define hla_robot1_en _c_hla_robot1_en
#define hla_robot2_en _c_hla_robot2_en
#define auto_mode_pause _c_auto_mode_pause
#define hla_night_mode _c_hla_night_mode
#define hla_zinc_again _c_hla_zinc_again
#define hla_correct_command _c_hla_correct_command
#define scheduler_stage _c_scheduler_stage
#endif
extern const short NIGHT_ZONES[9];
/* ======================== ROBOT CODE ======================== */
#define ROBOT_CMD_MASK 0xF000U
#define ROBOT_CMD_END_code 0x0000U
#define ROBOT_CMD_MOVE_TO_ZONE_code 0x1000U
#define ROBOT_CMD_MOVE_OFF_code 0x2000U
#define ROBOT_CMD_MOVE_ACCURATE_code 0x3000U
#define ROBOT_CMD_UP_code 0x4000U
#define ROBOT_CMD_DOWN_code 0x5000U
#define ROBOT_CMD_WAIT_code 0x6000U
#define ROBOT_CMD_TMR_SET_code 0x7000U
#define ROBOT_CMD_SET_LOCK_ZONE_code 0x8000U
#define ROBOT_CMD_CORRECT_AXIS_code 0x9000U
#define ROBOT_CMD_INC_ZONE_code 0xA000U
// перемещение с барабаном
#define ROBOT_WITH_BARREL 0x0800U
// опции зон
#define ROBOT_ZONE_ETCH 0x0400U
#define ROBOT_ZONE_GAL 0x0200U
#define ROBOT_ZONE_PARKING 0x0100U
// опции коррекции осей
#define ROBOT_AXIS_X 1
#define ROBOT_AXIS_Z 2
// макросы для генерации команд
#define ROBOT_CMD_END() (ROBOT_CMD_END_code)
#define ROBOT_CMD_MOVE_TO_ZONE(zone) (ROBOT_CMD_MOVE_TO_ZONE_code | (unsigned short)(zone & 0x00FF))
#define ROBOT_CMD_MOVE_TO_ZONE_WITH_BARREL(zone) (ROBOT_CMD_MOVE_TO_ZONE_code | ROBOT_WITH_BARREL | (unsigned short)(zone & 0x00FF))
#define ROBOT_CMD_MOVE_TO_PARKING() (ROBOT_CMD_MOVE_TO_ZONE_code | ROBOT_ZONE_PARKING)
#define ROBOT_CMD_MOVE_OFF() (ROBOT_CMD_MOVE_OFF_code)
#define ROBOT_CMD_MOVE_ACCURATE() (ROBOT_CMD_MOVE_ACCURATE_code)
#define ROBOT_CMD_UP() (ROBOT_CMD_UP_code)
#define ROBOT_CMD_UP_WITH_BARREL() (ROBOT_CMD_UP_code | ROBOT_WITH_BARREL)
#define ROBOT_CMD_DOWN() (ROBOT_CMD_DOWN_code)
#define ROBOT_CMD_DOWN_WITH_BARREL() (ROBOT_CMD_DOWN_code | ROBOT_WITH_BARREL)
#define ROBOT_CMD_WAIT(time) (ROBOT_CMD_WAIT_code | (unsigned short)(time & 0x0FFF))
#define ROBOT_CMD_TMR_SET(time) ((ROBOT_CMD_TMR_SET_code) | (unsigned short)(time & 0x0FFF))
#define ROBOT_CMD_SET_LOCK_ZONE(zone) ((ROBOT_CMD_SET_LOCK_ZONE_code) | (unsigned short)(zone & 0x00FF))
#define ROBOT_CMD_CORRECT_AXIS(axis) (ROBOT_CMD_CORRECT_AXIS_code | (unsigned short)axis)
#define ROBOT_CMD_INC_ZONE(arg) (ROBOT_CMD_INC_ZONE_code | (unsigned short)(arg))
/* ======================== DISABLED ZONES ======================== */
#define DISABLED_ETCH_1 0x0001
#define DISABLED_ETCH_2 0x0002
#define DISABLED_ETCH 0x0003
#define DISABLED_GAL_1 0x0004
#define DISABLED_GAL_2 0x0008
#define DISABLED_GAL_3 0x0010
#define DISABLED_GAL_4 0x0020
#define DISABLED_GAL_5 0x0040
#define DISABLED_GAL_6 0x0080
#define DISABLED_GAL_7 0x0100
#define DISABLED_GAL_8 0x0200
#define DISABLED_GAL 0x03FC
/* ======================== IO ======================== */
#define ROBOT1_X 1
#define ROBOT1_Z 2
#define ROBOT2_X 3
#define ROBOT2_Z 4
#define VFD_REG_D0_ADDR 4096
#define VFD_REG_M0_ADDR 2048
#define MB_CMD_WRITE_FLAG 5
#define MB_CMD_WRITE_REG 6
#define VFD_REG_D0_ADDR 4096
#define VFD_REG_M0_ADDR 2048
// смещение регистров M относительно M0
#define ROBOT_Z_CORRECT_STATUS_OFFSET 0
#define ROBOT_Z_CMD_EXECUTED_OFFSET 1
#define ROBOT_Z_CMD_UP_OFFSET 3
#define ROBOT_Z_CMD_DOWN_OFFSET 4
#define ROBOT_Z_CMD_CORRECT_OFFSET 5
#define ROBOT_X_CORRECT_STATUS_OFFSET 0
#define ROBOT_X_CMD_EXECUTED_OFFSET 1
#define ROBOT_X_CORRECT_SENSOR_OFFSET 2
#define ROBOT_X_CMD_MOVE_TO_ZONE_OFFSET 3
#define ROBOT_X_CMD_MOVE_TO_OFF_POS_OFFSET 4 // встать в смещенную позицию
#define ROBOT_X_CMD_MOVE_TO_COR_POS_OFFSET 5 // встать в точную позицию
#define ROBOT_X_CMD_CORRECT_OFFSET 6
#define ROBOT_X_CMD_CMD_PARKING_OFFSET 7
// смещение регистров D относительно D0
#define ROBOT_X_TARGET_ZONE_OFFSET 2
// адреса регистров в частотнике
#define ROBOT_Z_CORRECT_STATUS_ADDR VFD_REG_M0_ADDR
#define ROBOT_Z_CMD_EXECUTED_ADDR (VFD_REG_M0_ADDR + 1)
#define ROBOT_Z_CMD_UP_ADDR (VFD_REG_M0_ADDR + 3)
#define ROBOT_Z_CMD_DOWN_ADDR (VFD_REG_M0_ADDR + 4)
#define ROBOT_Z_CMD_CORRECT_ADDR (VFD_REG_M0_ADDR + 5)
#define ROBOT_X_CORRECT_STATUS_ADDR VFD_REG_M0_ADDR
#define ROBOT_X_CMD_EXECUTED_ADDR (VFD_REG_M0_ADDR + ROBOT_X_CMD_EXECUTED_OFFSET)
#define ROBOT_X_CORRECT_SENSOR_ADDR (VFD_REG_M0_ADDR + ROBOT_X_CORRECT_SENSOR_OFFSET)
#define ROBOT_X_CMD_MOVE_TO_ZONE_ADDR (VFD_REG_M0_ADDR + ROBOT_X_CMD_MOVE_TO_ZONE_OFFSET)
#define ROBOT_X_CMD_MOVE_TO_OFF_ADDR (VFD_REG_M0_ADDR + ROBOT_X_CMD_MOVE_TO_OFF_POS_OFFSET)
#define ROBOT_X_CMD_MOVE_TO_COR_ADDR (VFD_REG_M0_ADDR + ROBOT_X_CMD_MOVE_TO_COR_POS_OFFSET)
#define ROBOT_X_CMD_CORRECT_ADDR (VFD_REG_M0_ADDR + ROBOT_X_CMD_CORRECT_OFFSET)
#define ROBOT_X_CMD_PARKING_ADDR (VFD_REG_M0_ADDR + ROBOT_X_CMD_CMD_PARKING_OFFSET)
#define ROBOT_X_TARGET_ZONE_ADDR (VFD_REG_D0_ADDR + ROBOT_X_TARGET_ZONE_OFFSET)
/* ======================== UTILS FUNCTIONS ======================== */
/**
* Занята ли зона. Учитываются только барабаны, которые внизу
* @param zone зона для обнаружения
* @return true если занята, в противном случае false
*/
char zone_is_busy(short zone);
#define ROBOT_1 1
#define ROBOT_2 2
#define ROBOT_NONE -1
/**
* Функция, определяющая можно ли переместить барабан и куда его нужно переместить.
* @param bar указатель на барабан
* @param robot_id ID робота, нужно передавать всегда, в режиме одного робота учитывается время, в режиме двух роботов
* учитываются рабочие границы роботов. Для отключения учета времени и границ следует передать ROBOT_NONE
.
* @return Зону, куда нужно переместить барабан. Если значение < 0, то барабан переместить в данный момент невозможно.
*/
short can_move(struct barrel *bar, char robot_id);
/**
* Получить приоритет для операции перемещения барабана. Учитывает взаимное положение барабанов на линии и аттрибуты барабана
* @note Вызывать следует только если барабан подлежит перемещению (can_move
вернул значение >= 0)
* @param barrel_id номер барабана, для которого нужно вычислить приоритет.
* @return Приоритет операции. Чем больше число тем выше приоритет.
*/
short get_operation_priority(short barrel_id);
/**
* Удаление барабана из зоны, учитывает блокировку барабана роботом и положение барабана (нельзя удалить висящий барабан).
* @param zone Зона, из которой требуется удалить барабана.
* @return true, если барабан был удален, в противном случае false.
*/
char remove_barrel_from_zone(short zone);
/**
* Создание операции на перемещение барабана.
* @param barrel_id индекс барабана в структуре барабана, функцией напрямую не учитывается, но копируется в структуру кода робота
* @param start_zone зона, откуда нужно переместить барабан
* @param dest_zone зона, куда нужно переместить барабан (если ZONE_PASSIVATION то фактически после операции барабан окажется в зоне промывки 4а)
* @param robot_id ID робота, который должен выполнить операцию
*/
void create_operation(short barrel_id, const short start_zone, const short dest_zone, const short robot_id);
/**
* Активна ли зона цинкования или травления
* @param zone ROBOT_ZONE_ETCH или ROBOT_ZONE_GAL. Для других значений функция вернет false.
* @return true, если выбранная зона цинкования или травления доступна
*/
char is_accessible_zone(short zone);
/**
* Инкрементировать зону цинкования или зону травления.
* @param zone ROBOT_ZONE_ETCH или ROBOT_ZONE_GAL. Для других значений функция вернет false.
* @return true, если существует хотя бы одна зона, куда можно положить баран. При любых ошибках вернет false.
*/
char increment_zone(short zone);
/**
* Получение первой ночной зоны, то есть зоны куда нужно ложить ночной барабан
* @return номер зоны, либо -1 если зона занята или еще нужна для обслуживания других барабанов
*/
short get_first_night_zone();
#ifdef EMULATOR
/**
* Вывод структуры кода робота, работает только в эмуляторе.
* @param code структура кода робота, именно ее и будет выводить функция
* @param robot_id ID робота (1 или 2), нужно для вывода отладочной информации
* @param fd file descriptor, устройство куда нужно записать весь вывод
*/
void debug_print_robot_code(const struct robot_code *code, const short robot_id, int fd);
#endif
#ifdef __cplusplus
}
#endif
#endif //SDP_SCHEDULER_UTILS_H