#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