diff --git a/emulator.h b/emulator.h index c069ba1..e7d3a86 100644 --- a/emulator.h +++ b/emulator.h @@ -18,7 +18,6 @@ void scheduler_main(); // Флаги, которые есть в оригинальной программе на ПЛК, в "C global variables" // Кнопки с панели -extern char hla_auto_mode; extern char hla_night_mode; extern char hla_correct_command; diff --git a/scheduler.c b/scheduler.c index 708ffeb..ec0244b 100644 --- a/scheduler.c +++ b/scheduler.c @@ -11,87 +11,73 @@ struct scheduler_task { short scheduler_find_task(const struct scheduler_task* tasks, const short curr_pos) { - if (hla_night_mode) { - // надо просто найти самый левый барабан - short b = -1; // собсна барабан, который можно переместить - short z = ZONE_UNLOAD; // зона, ищем минимальную поэтому ставим максимальную - зону выгрузки - for (short i = 0; i < BARRELS_COUNT; i++) { - if (tasks[i].dest_zone >= 0 && tasks[i].start_zone <= z) { - b = i; - z = tasks[i].start_zone; + // для начала надо найти максимальный приоритет у операций + short max_priority = -1; + for (short i = 0; i < BARRELS_COUNT; i++) { + if (tasks[i].dest_zone >= 0) { + if (tasks[i].priority > max_priority) { + max_priority = tasks[i].priority; } } + } - return b; - } else { - // для начала надо найти максимальный приоритет у операций - short max_priority = -1; - for (short i = 0; i < BARRELS_COUNT; i++) { - if (tasks[i].dest_zone >= 0) { - if (tasks[i].priority > max_priority) { - max_priority = tasks[i].priority; - } - } + if (max_priority < 0) { + return -1; // тасков нет + } + + // ищем первый барабан слева, и ближайший справа + short left = -1, right = -1; + for (short i = 0; i < BARRELS_COUNT; i++) { + short target = tasks[i].start_zone; // фактическая зона откуда тащить барабан + if (tasks[i].dest_zone < 0) { + continue; } - if (max_priority < 0) { - return -1; // тасков нет + // чтобы не получилось перемещать барабаны с приоритетом ниже + if (tasks[i].priority < max_priority) { + continue; } - // ищем первый барабан слева, и ближайший справа - short left = -1, right = -1; - for (short i = 0; i < BARRELS_COUNT; i++) { - short target = tasks[i].start_zone; // фактическая зона откуда тащить барабан - if (tasks[i].dest_zone < 0) { - continue; - } - - // чтобы не получилось перемещать барабаны с приоритетом ниже - if (tasks[i].priority < max_priority) { - continue; - } - - if (curr_pos <= target) { - // это таск справа, надо найти ближайший - if (right == -1) { - right = i; - } else { - if (barrels[right].zone > target) { - right = i; - } - } + if (curr_pos <= target) { + // это таск справа, надо найти ближайший + if (right == -1) { + right = i; } else { - // таск слева, ищем максимально дальний (с минимальной зоной) - if (left == -1) { + if (barrels[right].zone > target) { + right = i; + } + } + } else { + // таск слева, ищем максимально дальний (с минимальной зоной) + if (left == -1) { + left = i; + } else { + if (barrels[left].zone > target) { left = i; - } else { - if (barrels[left].zone > target) { - left = i; - } } } } + } - // итого есть результат: есть ли таски, которые надо тащить вперед (и если надо то какой ближний), и есть первый таск - if (left < 0) { - return right; // вернем таск справа (если его нет, в переменной будет -1) - } - if (right < 0) { - return left; // если вдруг задачи справа не оказалось, вернем задачу слева если есть - } + // итого есть результат: есть ли таски, которые надо тащить вперед (и если надо то какой ближний), и есть первый таск + if (left < 0) { + return right; // вернем таск справа (если его нет, в переменной будет -1) + } + if (right < 0) { + return left; // если вдруг задачи справа не оказалось, вернем задачу слева если есть + } - // вычисляем что ближе - short ld = curr_pos - left; // левая дельта - short rd = right - curr_pos; // правая дельта + // вычисляем что ближе + short ld = curr_pos - left; // левая дельта + short rd = right - curr_pos; // правая дельта - // дальше сравниваем дельты - // по идее если они равны то с большим приоритетом робот поедет в левую часть, - // а левую дельту вообще уменьшу на 1, чтобы цель слева казалась ближе - if (rd > ld - 1) { - return left; - } else { - return right; - } + // дальше сравниваем дельты + // по идее если они равны то с большим приоритетом робот поедет в левую часть, + // а левую дельту вообще уменьшу на 1, чтобы цель слева казалась ближе + if (rd > ld - 1) { + return left; + } else { + return right; } } @@ -128,24 +114,24 @@ void scheduler_main() robot1_lock_zone = -1; robot2_lock_zone = -1; - // ставим всем барабанам которые в промывках флаг ночного барабана (кроме тех, что заняты роботами) - for (short i = 0; i < BARRELS_COUNT; i++) { - if (barrels[i].flags.is_exist && barrels[i].flags.robot == 0) { - const short zones[] = { - ZONE_LOAD_1, - ZONE_WASHING_1A, ZONE_WASHING_1B, - ZONE_WASHING_2A, ZONE_WASHING_2B, - ZONE_WASHING_3A, ZONE_WASHING_3B, - ZONE_WASHING_4A, ZONE_WASHING_4B - }; - for (short t = 0; t < 9; t++) { - if (barrels[i].zone == zones[t]) { - barrels[i].flags.is_night = -1; - break; - } - } - } - } +// // ставим всем барабанам которые в промывках флаг ночного барабана (кроме тех, что заняты роботами) +// for (short i = 0; i < BARRELS_COUNT; i++) { +// if (barrels[i].flags.is_exist && barrels[i].flags.robot == 0) { +// const short zones[] = { +// ZONE_LOAD_1, +// ZONE_WASHING_1A, ZONE_WASHING_1B, +// ZONE_WASHING_2A, ZONE_WASHING_2B, +// ZONE_WASHING_3A, ZONE_WASHING_3B, +// ZONE_WASHING_4A, ZONE_WASHING_4B +// }; +// for (short t = 0; t < 9; t++) { +// if (barrels[i].zone == zones[t]) { +// barrels[i].flags.is_night = -1; +// break; +// } +// } +// } +// } } if (scheduler_en) { diff --git a/utils.c b/utils.c index 967e0db..efc4e66 100644 --- a/utils.c +++ b/utils.c @@ -6,13 +6,22 @@ #include #include "emulator.h" #else -#include "main.h" +#include "utils.h" #endif #define LOCK_ZONE_BORDER 1 +const short NIGHT_ZONES[9] = { + ZONE_LOAD_1, + ZONE_WASHING_1A, ZONE_WASHING_1B, + ZONE_WASHING_2A, ZONE_WASHING_2B, + ZONE_WASHING_3A, ZONE_WASHING_3B, + ZONE_WASHING_4A, ZONE_WASHING_4B +}; + + char zone_is_busy(short zone) { for (short i = 0; i < BARRELS_COUNT; i++) { if (barrels[i].flags.is_exist && barrels[i].zone == zone) { @@ -23,6 +32,18 @@ char zone_is_busy(short zone) { } +short get_first_night_zone() { + // всего зон, куда можно сныкать барабаны (всего 9 мест: 8 промывок и выгрузка) + for (short i = 0; i < 9; i++) { + if (!zone_is_busy(NIGHT_ZONES[i])) { + return NIGHT_ZONES[i]; + } + } + + return -1; +} + + // TODO обновить метод для работы с двумя роботами // вернет можно ли ехать и главное куда ехать, если можно (нельзя если вернулось значение < 0) // -1 вернет что перемещать нельзя @@ -44,199 +65,186 @@ short can_move(struct barrel *bar, char robot_id) { return -2; } + // проверка ночного режима if (hla_night_mode) { - if (bar->flags.is_night) { + if (bar->flags.is_night && !bar->flags.is_empty) { return -1; } - // задача - найти первую свободную промывку - const short zones[] = { - ZONE_LOAD_1, - ZONE_WASHING_1A, ZONE_WASHING_1B, - ZONE_WASHING_2A, ZONE_WASHING_2B, - ZONE_WASHING_3A, ZONE_WASHING_3B, - ZONE_WASHING_4A, ZONE_WASHING_4B - }; - - // всего зон, куда можно сныкать барабаны (всего 9 мест: 8 промывок и выгрузка) - for (short i = 0; i < 9; i++) { - if (!zone_is_busy(zones[i])) { - return zones[i]; - } - } - return -1; } else { - // дальше нужно проверить, что можно передвигать бочку - short dest_zone = -1; - // если барабан ночной, то надо проверить выгрузку (туда выгружаются ночные барабаны) - if (bar->flags.is_night) { - if (!zone_is_busy(ZONE_LOAD_1)) { - dest_zone = ZONE_LOAD_1; + } + + // дальше нужно проверить, что можно передвигать бочку + short dest_zone = -1; + + // если барабан ночной, то надо проверить выгрузку (туда выгружаются ночные барабаны) + if (bar->flags.is_night) { + if (!zone_is_busy(ZONE_LOAD_1)) { + dest_zone = ZONE_LOAD_1; + } + } else { + switch (bar->zone) { + case ZONE_LOAD_2: + // загрузка 2, только в нее можно грузить новые барабаны, нужно обезжиривание + if (!zone_is_busy(ZONE_DEGREASING)) { + dest_zone = ZONE_DEGREASING; + } + break; + + case ZONE_DEGREASING: + // обезжиривание, нужна промывка 1А + if (!zone_is_busy(ZONE_WASHING_1A)) { + dest_zone = ZONE_WASHING_1A; + } + break; + + case ZONE_WASHING_1A: + // промывка 1А, нужна промывка 1Б + if (!zone_is_busy(ZONE_WASHING_1B)) { + dest_zone = ZONE_WASHING_1B; + } + break; + + case ZONE_WASHING_1B: + // промывка 1Б, нужно травление (зоны 5-6) + if (etching_zone < 0) { + break; + } + if (!zone_is_busy((short)(ZONE_ETCHING_1 + etching_zone))) { + dest_zone = (short)(ZONE_ETCHING_1 + etching_zone); + } + break; + + case ZONE_ETCHING_1: + case ZONE_ETCHING_2: + // травление, нужна промывка 2А + if (!zone_is_busy(ZONE_WASHING_2A)) { + dest_zone = ZONE_WASHING_2A; + } + break; + + case ZONE_WASHING_2A: + // промывка 2А, нужна промывка 2Б + if (!zone_is_busy(ZONE_WASHING_2B)) { + dest_zone = ZONE_WASHING_2B; + } + break; + + case ZONE_WASHING_2B: + // промывка 2Б, нужно цинкование (зоны 9-16) + if (galvanizing_zone < 0) { + break; + } + if (!zone_is_busy((short)(ZONE_GALVANIZING_1 + galvanizing_zone))) { + dest_zone = (short)(ZONE_GALVANIZING_1 + galvanizing_zone); + } + break; + + case ZONE_GALVANIZING_1: + case ZONE_GALVANIZING_2: + case ZONE_GALVANIZING_3: + case ZONE_GALVANIZING_4: + case ZONE_GALVANIZING_5: + case ZONE_GALVANIZING_6: + case ZONE_GALVANIZING_7: + case ZONE_GALVANIZING_8: + // цинкование, требуется чтобы в зонах 17-22 было максимум 2 барабана (3 барабана для этой части линии - максимум) + if (!zone_is_busy(ZONE_WASHING_3A)) { + short count = 0; + // если зона 17 свободна, то диапазон начнется с 3Б + for (short i = ZONE_WASHING_3B; i <= (short)ZONE_UNLOAD; i++) { + if (zone_is_busy(i)) { + count++; + } + } + if (count < 3) { + dest_zone = ZONE_WASHING_3A; + } + } + break; + + case ZONE_WASHING_3A: + // промывка 3А, перекладываем в промывку 3Б + if (!zone_is_busy(ZONE_WASHING_3B)) { + dest_zone = ZONE_WASHING_3B; + } + break; + + case ZONE_WASHING_3B: + // это перед пассивацией, требует свободную промывку 4А и на всякий случай свободную пассивацию + if (!zone_is_busy(ZONE_PASSIVATION) && !zone_is_busy(ZONE_WASHING_4A)) { + dest_zone = ZONE_PASSIVATION; + } + // это атомарная операция, по идее вносить барабан в пассивацию нельзя + break; + + case ZONE_PASSIVATION: + // процесс пассивации, нужна промывка 4A + // чисто теоретически сюда никогда не попадем, но если вдруг выстрелит пусть будет + if (!zone_is_busy(ZONE_WASHING_4A)) { + dest_zone = ZONE_WASHING_4A; + } + break; + + case ZONE_WASHING_4A: + // промывка 4А, перекладываем в промывку 4Б + if (!zone_is_busy(ZONE_WASHING_4B)) { + dest_zone = ZONE_WASHING_4B; + } + break; + + case ZONE_WASHING_4B: + // процесс пассивации, нужна промывка 4B (зона 21) (потому что сейчас я в 4A) + if (!zone_is_busy(ZONE_UNLOAD)) { + dest_zone = ZONE_UNLOAD; + } + break; + + case ZONE_UNLOAD: + // последняя промывка, нужно разрешение на выгрузку + if (one_robot_mode && button_unload) { + // нужно промывку загрузку 0 + if (!zone_is_busy(ZONE_LOAD_1)) { + dest_zone = ZONE_LOAD_1; + } + } + break; + } + } + + if (!one_robot_mode) { + if (robot_id == 1) { + // если робот 1, то это старый, который ближе к концу линнии. + // Ему нельзя ехать если хоть одна из зон <= max(r2_pos, r2_lock) + кол-во пограничных зон + short border = robot2.dx.current_zone; + if (robot2_lock_zone > border) { + border = robot2_lock_zone; + } + border += LOCK_ZONE_BORDER; + + if (bar->zone <= border || dest_zone <= border) { + dest_zone = -1; } } else { - switch (bar->zone) { - case ZONE_LOAD_2: - // загрузка 2, только в нее можно грузить новые барабаны, нужно обезжиривание - if (!zone_is_busy(ZONE_DEGREASING)) { - dest_zone = ZONE_DEGREASING; - } - break; + // если робот 2, то это новый, который ближе к началу линнии. + // Ему нельзя ехать если хоть одна из зон >= max(r2_pos, r2_lock) - кол-во пограничных зон + short border = robot1.dx.current_zone; + if (robot1_lock_zone < border) { + border = robot1_lock_zone; + } + border -= LOCK_ZONE_BORDER; - case ZONE_DEGREASING: - // обезжиривание, нужна промывка 1А - if (!zone_is_busy(ZONE_WASHING_1A)) { - dest_zone = ZONE_WASHING_1A; - } - break; - - case ZONE_WASHING_1A: - // промывка 1А, нужна промывка 1Б - if (!zone_is_busy(ZONE_WASHING_1B)) { - dest_zone = ZONE_WASHING_1B; - } - break; - - case ZONE_WASHING_1B: - // промывка 1Б, нужно травление (зоны 5-6) - if (etching_zone < 0) { - break; - } - if (!zone_is_busy((short)(ZONE_ETCHING_1 + etching_zone))) { - dest_zone = (short)(ZONE_ETCHING_1 + etching_zone); - } - break; - - case ZONE_ETCHING_1: - case ZONE_ETCHING_2: - // травление, нужна промывка 2А - if (!zone_is_busy(ZONE_WASHING_2A)) { - dest_zone = ZONE_WASHING_2A; - } - break; - - case ZONE_WASHING_2A: - // промывка 2А, нужна промывка 2Б - if (!zone_is_busy(ZONE_WASHING_2B)) { - dest_zone = ZONE_WASHING_2B; - } - break; - - case ZONE_WASHING_2B: - // промывка 2Б, нужно цинкование (зоны 9-16) - if (galvanizing_zone < 0) { - break; - } - if (!zone_is_busy((short)(ZONE_GALVANIZING_1 + galvanizing_zone))) { - dest_zone = (short)(ZONE_GALVANIZING_1 + galvanizing_zone); - } - break; - - case ZONE_GALVANIZING_1: - case ZONE_GALVANIZING_2: - case ZONE_GALVANIZING_3: - case ZONE_GALVANIZING_4: - case ZONE_GALVANIZING_5: - case ZONE_GALVANIZING_6: - case ZONE_GALVANIZING_7: - case ZONE_GALVANIZING_8: - // цинкование, требуется чтобы в зонах 17-22 было максимум 2 барабана (3 барабана для этой части линии - максимум) - if (!zone_is_busy(ZONE_WASHING_3A)) { - short count = 0; - // если зона 17 свободна, то диапазон начнется с 3Б - for (short i = ZONE_WASHING_3B; i <= (short)ZONE_UNLOAD; i++) { - if (zone_is_busy(i)) { - count++; - } - } - if (count < 3) { - dest_zone = ZONE_WASHING_3A; - } - } - break; - - case ZONE_WASHING_3A: - // промывка 3А, перекладываем в промывку 3Б - if (!zone_is_busy(ZONE_WASHING_3B)) { - dest_zone = ZONE_WASHING_3B; - } - break; - - case ZONE_WASHING_3B: - // это перед пассивацией, требует свободную промывку 4А и на всякий случай свободную пассивацию - if (!zone_is_busy(ZONE_PASSIVATION) && !zone_is_busy(ZONE_WASHING_4A)) { - dest_zone = ZONE_PASSIVATION; - } - // это атомарная операция, по идее вносить барабан в пассивацию нельзя - break; - - case ZONE_PASSIVATION: - // процесс пассивации, нужна промывка 4A - // чисто теоретически сюда никогда не попадем, но если вдруг выстрелит пусть будет - if (!zone_is_busy(ZONE_WASHING_4A)) { - dest_zone = ZONE_WASHING_4A; - } - break; - - case ZONE_WASHING_4A: - // промывка 4А, перекладываем в промывку 4Б - if (!zone_is_busy(ZONE_WASHING_4B)) { - dest_zone = ZONE_WASHING_4B; - } - break; - - case ZONE_WASHING_4B: - // процесс пассивации, нужна промывка 4B (зона 21) (потому что сейчас я в 4A) - if (!zone_is_busy(ZONE_UNLOAD)) { - dest_zone = ZONE_UNLOAD; - } - break; - - case ZONE_UNLOAD: - // последняя промывка, нужно разрешение на выгрузку - if (one_robot_mode && button_unload) { - // нужно промывку загрузку 0 - if (!zone_is_busy(ZONE_LOAD_1)) { - dest_zone = ZONE_LOAD_1; - } - } - break; + if (bar->zone >= border || dest_zone >= border) { + dest_zone = -1; } } - - if (!one_robot_mode) { - if (robot_id == 1) { - // если робот 1, то это старый, который ближе к концу линнии. - // Ему нельзя ехать если хоть одна из зон <= max(r2_pos, r2_lock) + кол-во пограничных зон - short border = robot2.dx.current_zone; - if (robot2_lock_zone > border) { - border = robot2_lock_zone; - } - border += LOCK_ZONE_BORDER; - - if (bar->zone <= border || dest_zone <= border) { - dest_zone = -1; - } - } else { - // если робот 2, то это новый, который ближе к началу линнии. - // Ему нельзя ехать если хоть одна из зон >= max(r2_pos, r2_lock) - кол-во пограничных зон - short border = robot1.dx.current_zone; - if (robot1_lock_zone < border) { - border = robot1_lock_zone; - } - border -= LOCK_ZONE_BORDER; - - if (bar->zone >= border || dest_zone >= border) { - dest_zone = -1; - } - } - } - - return dest_zone; } + + return dest_zone; } -// выставляет приоритет операции (зависит только от зоны, в которой робот находится) +// выставляет приоритет операции short get_operation_priority(short barrel_id) { // сделать приоритет на барабан, который больше всего ждет if (barrels[barrel_id].zone >= ZONE_GALVANIZING_1 && barrels[barrel_id].zone <= ZONE_GALVANIZING_8) { diff --git a/utils.h b/utils.h index 03fe251..7e86c36 100644 --- a/utils.h +++ b/utils.h @@ -224,8 +224,12 @@ extern char scheduler_start_signal; #define hla_robot2_en _c_hla_robot2_en #define auto_mode_pause _c_auto_mode_pause +#define hla_night_mode _c_hla_night_mode + #endif +extern const short NIGHT_ZONES[9]; + #define ROBOT_CMD_MASK (short)0xF000 #define ROBOT_CMD_END_code (short)0x0000