diff --git a/emulator.cpp b/emulator.cpp index 1f6d732..606c1c8 100644 --- a/emulator.cpp +++ b/emulator.cpp @@ -10,7 +10,7 @@ #include "robot.h" -// закомментить когда надо будет отключить +// закомментируй когда надо будет отключить //#define DEBUG_CORRECTION @@ -207,7 +207,7 @@ static void collectBarrelsStatistic() { continue; } if (barrels[i].flags.robot == 0 && barrels[i].software_timer < 0) { - // время отрицательное, вычитаем его чтобы убрать минус + // время отрицательное, вычитаем его, чтобы убрать минус barrels_time -= barrels[i].software_timer; } } diff --git a/scheduler.c b/scheduler.c index 9f60ea0..c98aa73 100644 --- a/scheduler.c +++ b/scheduler.c @@ -4,7 +4,6 @@ struct scheduler_task { - short start_zone; // стартовая зона short dest_zone; // конечная зона short priority; // приоритет, чем больше тем выше, по умолчанию 0 }; @@ -28,7 +27,7 @@ short scheduler_find_task(const struct scheduler_task* tasks, const short curr_p // ищем первый барабан слева, и ближайший справа short left = -1, right = -1; for (short i = 0; i < BARRELS_COUNT; i++) { - short target = tasks[i].start_zone; // фактическая зона откуда тащить барабан + short target = barrels[i].zone; // фактическая зона откуда тащить барабан if (tasks[i].dest_zone < 0) { continue; } @@ -86,8 +85,6 @@ void schedule_one_robot(const short robot_id) { struct scheduler_task tasks[BARRELS_COUNT]; for (short i = 0; i < BARRELS_COUNT; i++) { - // для каждой задачи: - tasks[i].start_zone = barrels[i].zone; // определяем можно ли ее выполнить и что вообще нужно выполнить tasks[i].dest_zone = can_move(barrels + i, robot_id); if (tasks[i].dest_zone >= 0) { @@ -108,11 +105,9 @@ void schedule_one_robot(const short robot_id) { if (target_task >= 0) { if (robot_id == ROBOT_1) { - create_operation(&robot1_code, target_task, tasks[target_task].start_zone, tasks[target_task].dest_zone, - current_zone, robot_id); + create_operation(target_task, barrels[target_task].zone, tasks[target_task].dest_zone, robot_id); } else { - create_operation(&robot2_code, target_task, tasks[target_task].start_zone, tasks[target_task].dest_zone, - current_zone, robot_id); + create_operation(target_task, barrels[target_task].zone, tasks[target_task].dest_zone, robot_id); } } } diff --git a/utils.c b/utils.c index b625c18..ea5b4c1 100644 --- a/utils.c +++ b/utils.c @@ -24,7 +24,7 @@ const short NIGHT_ZONES[9] = { char zone_is_busy(short zone) { for (short i = 0; i < BARRELS_COUNT; i++) { - if (barrels[i].flags.is_exist && barrels[i].zone == zone) { + if (barrels[i].flags.is_exist && barrels[i].zone == zone && !barrels[i].flags.is_up) { return 1; } } @@ -33,7 +33,6 @@ char zone_is_busy(short zone) { short get_first_night_zone() { - // TODO сделать корректное вычисление ночной зоны // всего зон, куда можно сныкать барабаны (всего 9 мест: загрузка 1 и 8 промывок) for (short nz = 0; nz < 9; nz++) { char found = 0; @@ -67,13 +66,15 @@ short _get_dest_zone(struct barrel *bar, char robot_id) { } else { return -1; } - } else { + } else if (robot_id == ROBOT_2) { // робот 2 всегда кидает барабаны в загрузку 1, но только дальше зоны обмена он не имеет права брать if (bar->zone <= hla_exchange_zone) { return ZONE_LOAD_1; } else { return -1; } + } else { + return ZONE_LOAD_1; } } } @@ -209,9 +210,7 @@ short _get_dest_zone(struct barrel *bar, char robot_id) { return -1; } -// вернет можно ли ехать и главное куда ехать, если можно (нельзя если вернулось значение < 0) -// robot_id - 1 или 2 для роботов или -1 без привязки к конкретному роботу -// -1 вернет что перемещать нельзя + short can_move(struct barrel *bar, char robot_id) { if (robot_id != ROBOT_NONE && robot_id != ROBOT_1 && robot_id != ROBOT_2) { return -3; @@ -249,9 +248,9 @@ short can_move(struct barrel *bar, char robot_id) { #ifndef EMULATOR if (approximate_time > 1) { - approximate_time = ((approximate_time - 1) * 3) + 6; + approximate_time = ((approximate_time - 1) * 3) + 4; } else if (approximate_time == 1) { - approximate_time = 8; + approximate_time = 5; } #endif @@ -270,7 +269,7 @@ short can_move(struct barrel *bar, char robot_id) { // учитывать границы только в режиме двух роботов и с привязкой к роботу if (!one_robot_mode && dest_zone >= 0 && robot_id != ROBOT_NONE) { if (robot_id == 1) { - // если робот 1, то это старый, который ближе к концу линнии. + // если робот 1, то это старый, который ближе к концу линии. // Ему нельзя ехать если хоть одна из зон <= max(r2_pos, r2_lock) + кол-во пограничных зон short border = robot2.dx.current_zone; if (border < robot2_lock_zone) { @@ -286,7 +285,7 @@ short can_move(struct barrel *bar, char robot_id) { dest_zone = -6; } } else { - // если робот 2, то это новый, который ближе к началу линнии. + // если робот 2, то это новый, который ближе к началу линии. // Ему нельзя ехать если хоть одна из зон >= max(r2_pos, r2_lock) - кол-во пограничных зон short border = robot1.dx.current_zone; if (border > robot1_lock_zone) { @@ -308,7 +307,6 @@ short can_move(struct barrel *bar, char robot_id) { } -// выставляет приоритет операции, предполагается что ее можно выполнить short get_operation_priority(short barrel_id) { // если барабан пустой и не в ночном режиме, приоритет ему 2 if (barrels[barrel_id].flags.is_empty && !barrels[barrel_id].flags.is_night) { @@ -495,8 +493,19 @@ void debug_print_robot_code(const struct robot_code *code, const short robot_id, #endif -void create_operation(struct robot_code *code, short barrel_id, const short start_zone, const short dest_zone, - const short current_zone, const short robot_id) { +void create_operation(short barrel_id, const short start_zone, const short dest_zone, const short robot_id) { + short current_zone; + struct robot_code *code; + if (robot_id == ROBOT_1) { + current_zone = robot1.dx.current_zone; + code = &robot1_code; + } else if (robot_id == ROBOT_2) { + current_zone = robot2.dx.current_zone; + code = &robot2_code; + } else { + return; + } + // создаем код транзакции, пока обычный if (barrel_id >= BARRELS_COUNT) { barrel_id = -1; diff --git a/utils.h b/utils.h index c16b1ac..396e90f 100644 --- a/utils.h +++ b/utils.h @@ -130,24 +130,9 @@ struct robot_regs { // NOTE первой командой на любую транзакцию должна стоять команда опустить траверсу (в 22 зоне по идее никогда не закончим) struct robot_code { - short barrel_id; // нужен ID барабана, если + short barrel_id; // если требуются операции с барабаном, то для корректного исполнения нужно указать значение >= 0 short PC; // когда -1, код не выполняется - - /* - * система команд, которая нужна: (квадратные скобки - аргумент это младшие 14 бит) - * 0 (смещение: да () ? нет): установить смещение (да - встанет в смещенную позицию, нет - в точную) - * 1 (опция с барабаном) [поднять (1) | опустить]: поднять/опустить траверсу (перед поднятием ожидать если таймер барабана не истек) - * 2 (опция с барабаном) [зона]: съебаться в зону - * 3 [сек]: пауза на нужное количество секунд - * 4 [время]: установить таймер барабану - * 5 (ETCH(1) | GAL (2)) [зона]: установить зону блокировки, умеет использовать автоинкримент зоны гальваники или обезжиривания - * 6 [X(1) | Y(2)]: скорректировать ось - * 15: конец - * - * формат команды: (команда, старший байт) [младший байт, аргумент команды (если есть)] [слово, аргумент если команда требует] - */ unsigned short code[16]; // формат кода: [команды] <команда 0> - }; @@ -252,6 +237,8 @@ extern short scheduler_stage; 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 @@ -302,7 +289,7 @@ extern const short NIGHT_ZONES[9]; #define ROBOT_CMD_INC_ZONE(arg) (ROBOT_CMD_INC_ZONE_code | (unsigned short)(arg)) -/* ======================== DISABLED ZONES DEFS ======================== */ +/* ======================== DISABLED ZONES ======================== */ #define DISABLED_ETCH_1 0x0001 #define DISABLED_ETCH_2 0x0002 @@ -318,7 +305,8 @@ extern const short NIGHT_ZONES[9]; #define DISABLED_GAL_8 0x0200 #define DISABLED_GAL 0x03FC -/* ======================== IO DEFS ======================== */ + +/* ======================== IO ======================== */ #define ROBOT1_X 1 #define ROBOT1_Z 2 @@ -329,8 +317,6 @@ extern const short NIGHT_ZONES[9]; #define VFD_REG_D0_ADDR 4096 #define VFD_REG_M0_ADDR 2048 -/* ======================== ROBOT DEFS ======================== */ - #define MB_CMD_WRITE_FLAG 5 #define MB_CMD_WRITE_REG 6 @@ -376,6 +362,13 @@ extern const short NIGHT_ZONES[9]; #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); @@ -383,14 +376,38 @@ char zone_is_busy(short zone); #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); -void create_operation(struct robot_code *code, const short barrel_id, const short start_zone, const short dest_zone, - const short current_zone, const short robot_id); +/** + * Создание операции на перемещение барабана. + * @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); /** * Активна ли зона цинкования или травления @@ -406,9 +423,19 @@ char is_accessible_zone(short zone); */ 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