diff --git a/README.md b/README.md index 9f955d8..406cf00 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # sdp-scheduler +## Ограничения программы + +* нельзя отключить сразу все зоны цинкования или травления +* коррекцию нужно описать так, чтобы не произошло ничего страшного +* время скапывания нельзя поставить больше 200 секунд (в текущей реализации можно до 8К секунд) +* время каждого процесса не больше чем 32К секунд (можно уменьшить до 8К для упрощения логики) + diff --git a/emulator.cpp b/emulator.cpp index 7852692..7c50deb 100644 --- a/emulator.cpp +++ b/emulator.cpp @@ -174,7 +174,7 @@ static void open_socket() { } } -extern "C" struct barrel makeBarrel(short flags, short zone, short timer, short process); +extern "C" struct barrel makeBarrel(short flags, short zone, short timer); int main() { open_socket(); @@ -185,7 +185,7 @@ int main() { // b.zone = (short) abs(random() % 20); // } - barrels[5] = makeBarrel(1, 10, 3, PROCESS_WASHING_3A); + barrels[5] = makeBarrel(1, 10, 3); current_tic = 0; const char* message = nullptr; diff --git a/emulator.h b/emulator.h index bcf6090..33dcfbe 100644 --- a/emulator.h +++ b/emulator.h @@ -16,6 +16,8 @@ extern char schedulerLoadButton1; extern char schedulerLoadButton2; extern char schedulerOneRobotMode; +extern short etching_zone, galvanizing_zone; + void scheduler_main(); @@ -49,8 +51,8 @@ extern char button_unload_remove; // Переменные, которые надо добавить в C Global variables // код для роботов -extern robot_code robot1_code; -extern robot_code robot2_code; +extern struct robot_code robot1_code; +extern struct robot_code robot2_code; // lock-зоны, нельзя двигаться за них и за робота diff --git a/robot.cpp b/robot.cpp index ffe0a0e..1a99b16 100644 --- a/robot.cpp +++ b/robot.cpp @@ -19,7 +19,7 @@ static short get_barrel(char robot_id) { } // true означает что движение закончено -static bool robot_move(robot_regs& r, int target, char robot_id) { +static bool robot_move(robot_regs& r, short target, char robot_id) { // после перемещения мы явно в точной позиции if (robot_id == 1) { robot1_offset_pos = false; @@ -39,167 +39,21 @@ static bool robot_move(robot_regs& r, int target, char robot_id) { return false; } -static void emulate_robot(robot_cmd& cmd, robot_regs& r, char robot_id) { - auto barrel = get_barrel(robot_id); - switch (cmd.cmd) { - case 1: - // команда просто уехать - switch (cmd.step) { - case 0: - // двигаемся в сторону цели - if (robot_move(r, cmd.args[0], robot_id)) { - cmd.step++; - } - break; - default: - cmd.cmd = 0; - cmd.step = 0; - } - break; - - case 2: - // команда взять барабан и увезти его куда положено - switch (cmd.step) { - case 0: - // двигаемся в сторону барабана - if (robot_move(r, cmd.args[0], robot_id)) { - cmd.step++; - } - break; - - case 1: - // поднимаем траверсу - r.mz.is_up = 1; - if (barrel != -1) { - barrels[barrel].flags.is_up = 1; - } - cmd.step++; - break; - - case 2: - // двигаемся в сторону выгрузки - if (robot_move(r, cmd.args[1], robot_id)) { - cmd.step++; - } - break; - - case 3: - // опускаем траверсу - r.mz.is_up = 0; - if (barrel != -1) { - barrels[barrel].flags.is_up = 0; - } - // ну и тут же конец - - default: - cmd.cmd = 0; - cmd.step = 0; - } - break; - - case 3: - // команда пассивация - switch (cmd.step) { - case 0: - // двигаемся в 18 зону - if (robot_move(r, 18, robot_id)) { - cmd.step++; - } - break; - - case 1: - // поднимаем траверсу - r.mz.is_up = 1; - if (barrel != -1) { - barrels[barrel].flags.is_up = 1; - } - cmd.step++; - break; - - case 2: - // двигаемся в 19 зону - if (robot_move(r, 19, robot_id)) { - cmd.step++; - } - break; - - case 3: - // опускаем траверсу - r.mz.is_up = 0; - if (barrel != -1) { - barrels[barrel].flags.is_up = 0; - barrels[barrel].software_timer = barrels[barrel].time_passivation; - } - cmd.step++; - break; - - case 4: - // ждем пока барабан отстоит таймер в пассивации - if (barrel != -1) { - if (barrels[barrel].software_timer <= 0) { - cmd.step++; - } - } - break; - - case 5: - // поднимаем траверсу - r.mz.is_up = 1; - if (barrel != -1) { - barrels[barrel].flags.is_up = 1; - } - cmd.step++; - break; - - case 6: - // двигаемся в 20 зону - if (robot_move(r, 20, robot_id)) { - cmd.step++; - } - break; - - case 7: - // опускаем траверсу - r.mz.is_up = 0; - if (barrel != -1) { - barrels[barrel].flags.is_up = 0; - // и тут же ставим время промывки барабана - barrels[barrel].software_timer = barrels[barrel].time_washing_4a; - } - // ну и тут же конец - - default: - cmd.cmd = 0; - cmd.step = 0; - } - break; - - - default: - cmd.cmd = 0; - cmd.step = 0; - } - - if (r.mz.is_up) { - if (barrel != -1) { - barrels[barrel].zone = r.dx.current_zone; - } - } -} - - -static void emulate_robot_v2(robot_code* code, robot_regs& r, char robot_id) { - if (code->PC < 0) { +static void emulate_robot(robot_code &code, robot_regs& r, char robot_id) { + if (code.PC < 0) { return; } - const short cmd_arg = code->code[code->PC] & (~ROBOT_CMD_MASK); + const short cmd_arg = code.code[code.PC] & (~ROBOT_CMD_MASK); - switch (code->code[code->PC] & ROBOT_CMD_MASK) { + switch (code.code[code.PC] & ROBOT_CMD_MASK) { case ROBOT_CMD_MOVE_TO_ZONE: // двигаемся в сторону цели - if (robot_move(r, cmd_arg, robot_id)) { - code->PC++; + if (robot_move(r, cmd_arg & (~ROBOT_WITH_BARREL), robot_id)) { + code.PC++; + } + if (cmd_arg & ROBOT_WITH_BARREL && code.barrel_id >= 0) { + barrels[code.barrel_id].zone = r.dx.current_zone; } break; @@ -209,38 +63,42 @@ static void emulate_robot_v2(robot_code* code, robot_regs& r, char robot_id) { } else { robot2_offset_pos = true; } - code->PC++; + code.PC++; break; case ROBOT_CMD_UP: - if (code->barrel_id >= 0) { - barrels[code->barrel_id].flags.is_up = true; + if (code.barrel_id >= 0 && cmd_arg) { + // не давать ехать перед тем как истечет таймер + if (barrels[code.barrel_id].software_timer > 0) { + break; + } + barrels[code.barrel_id].flags.is_up = true; r.mz.is_up = 1; } - code->PC++; + code.PC++; break; // в эмуляторе не важно где я, поэтому тут обе команды вниз обрабатываются одинаково case ROBOT_CMD_DOWN: case ROBOT_CMD_DOWN_2: - if (code->barrel_id >= 0) { - barrels[code->barrel_id].flags.is_up = false; + if (code.barrel_id >= 0 && cmd_arg) { + barrels[code.barrel_id].flags.is_up = false; r.mz.is_up = 0; } - code->PC++; + code.PC++; break; case ROBOT_CMD_WAIT: std::cout << "robot " << robot_id << " wait " << cmd_arg << " secs..." << std::endl; - code->PC++; + code.PC++; break; case ROBOT_CMD_TMR_SET: - if (code->barrel_id >= 0) { - barrels[code->barrel_id].software_timer = code->code[code->PC + 1]; + if (code.barrel_id >= 0) { + barrels[code.barrel_id].software_timer = code.code[code.PC + 1]; r.mz.is_up = 0; } - code->PC += 2; + code.PC += 2; break; case ROBOT_CMD_SET_LOCK_ZONE: @@ -249,31 +107,46 @@ static void emulate_robot_v2(robot_code* code, robot_regs& r, char robot_id) { } else { robot2_lock_zone = cmd_arg; } - code->PC += 2; + code.PC += 2; break; - case ROBOT_CMD_CORRECT_X: - std::cout << "robot " << robot_id << " correct axis X..." << std::endl; - r.dz.current_zone = 0; - r.mx.correct_status = true; - code->PC++; + case ROBOT_CMD_CORRECT_AXIS: + if (cmd_arg == ROBOT_AXIS_X) { + std::cout << "robot " << robot_id << " correct axis X..." << std::endl; + r.dz.current_zone = 0; + r.mx.correct_status = true; + } else if (cmd_arg == ROBOT_AXIS_Z) { + std::cout << "robot " << robot_id << " correct axis Z..." << std::endl; + r.mz.is_up = true; + r.mz.correct_status = true; + } else { + std::cout << "ERROR: R" << robot_id << " AXIS CORRECT - INCORRECT ARGUMENT VALUE " << cmd_arg << std::endl; + } + + code.PC++; break; - case ROBOT_CMD_CORRECT_Z: - std::cout << "robot " << robot_id << " correct axis Z..." << std::endl; - r.mz.is_up = true; - r.mz.correct_status = true; - code->PC++; + case ROBOT_CMD_INC_ZONE: + if (cmd_arg == ROBOT_ZONE_ETCH) { + std::cout << "robot " << robot_id << " increment etching..." << std::endl; + etching_zone = (etching_zone + 1) & 1; + } else if (cmd_arg == ROBOT_ZONE_GAL) { + std::cout << "robot " << robot_id << " increment galvanic..." << std::endl; + galvanizing_zone = (galvanizing_zone + 1) & 0x07; + } else { + std::cout << "ERROR: R" << robot_id << " INCREMENT ZONE - INCORRECT ARGUMENT VALUE " << cmd_arg << std::endl; + } + code.PC++; break; case ROBOT_CMD_END: default: - code->PC = -1; + code.PC = -1; } } void robot_main() { - emulate_robot(robot1_cmd, robot1, 1); - emulate_robot(robot2_cmd, robot2, 2); + emulate_robot(robot1_code, robot1, 1); + emulate_robot(robot2_code, robot2, 2); } diff --git a/scheduler.c b/scheduler.c index c83fc64..0798c54 100644 --- a/scheduler.c +++ b/scheduler.c @@ -46,118 +46,125 @@ short can_move(struct barrel* bar) { // дальше нужно проверить, что можно передвигать бочку - switch (bar->curr_process) { - case PROCESS_NONE: - // загрузка, нужно обезжиривание (зона 2) - if (!zone_is_busy(2)) { - return 2; + switch (bar->zone) { + case ZONE_LOAD_2: + // загрузка 2, только в нее можно грузить новые барабаны, нужно обезжиривание + if (!zone_is_busy(ZONE_DEGREASING)) { + return ZONE_DEGREASING; } break; - case PROCESS_DEFATTING: - // обезжиривание, нужна промывка 1А (зона 3) - if (!zone_is_busy(3)) { - return 3; + case ZONE_DEGREASING: + // обезжиривание, нужна промывка 1А + if (!zone_is_busy(ZONE_WASHING_1A)) { + return ZONE_WASHING_1A; } break; - case PROCESS_WASHING_1A: - // промывка 1А, нужна промывка 1Б (зона 4) - if (!zone_is_busy(4)) { - return 4; + case ZONE_WASHING_1A: + // промывка 1А, нужна промывка 1Б + if (!zone_is_busy(ZONE_WASHING_1B)) { + return ZONE_WASHING_1B; } break; - case PROCESS_WASHING_1B: + case ZONE_WASHING_1B: // промывка 1Б, нужно травление (зоны 5-6) - if (!zone_is_busy(5 + etching_zone)) { - return 5 + etching_zone; + if (!zone_is_busy(ZONE_ETCHING_1 + etching_zone)) { + return ZONE_ETCHING_1 + etching_zone; } break; - case PROCESS_ETCHING: - // травление, нужна промывка 2А (зона 7) - if (!zone_is_busy(7)) { - return 7; + case ZONE_ETCHING_1: + case ZONE_ETCHING_2: + // травление, нужна промывка 2А + if (!zone_is_busy(ZONE_WASHING_2A)) { + return ZONE_WASHING_2A; } break; - case PROCESS_WASHING_2A: - // промывка 2А, нужна промывка 2Б (зона 8) - if (!zone_is_busy(8)) { - return 8; + case ZONE_WASHING_2A: + // промывка 2А, нужна промывка 2Б + if (!zone_is_busy(ZONE_WASHING_2B)) { + return ZONE_WASHING_2B; } break; - case PROCESS_WASHING_2B: + case ZONE_WASHING_2B: // промывка 2Б, нужно цинкование (зоны 9-16) - if (!zone_is_busy(9 + galvanizing_zone)) { - return 9 + galvanizing_zone; + if (!zone_is_busy(ZONE_GALVANIZING_1 + galvanizing_zone)) { + return ZONE_GALVANIZING_1 + galvanizing_zone; } break; - case PROCESS_GALVANIZING: + 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; - for (short i = 17; i <= 22; i++) { + // если зона 17 свободна, то диапазон начнется с 3Б + for (short i = ZONE_WASHING_3B; i <= ZONE_UNLOAD; i++) { if (zone_is_busy(i)) { count++; } } - if (count < 3 && !zone_is_busy(17)) { - return 17; + if (count < 3) { + return ZONE_WASHING_3A; } } break; - case PROCESS_WASHING_3A: - // промывка 3А, перекладываем в промывку 3Б (зона 18) - if (!zone_is_busy(18)) { - return 18; + case ZONE_WASHING_3A: + // промывка 3А, перекладываем в промывку 3Б + if (!zone_is_busy(ZONE_WASHING_3B)) { + return ZONE_WASHING_3B; } break; - case PROCESS_WASHING_3B: - // это перед пассивацией, требует свободную промывку 4А (зона 20) и на всякий случай свободную пассивацию (зона 19) - if (!zone_is_busy(19) && !zone_is_busy(20)) { - return -2; + case ZONE_WASHING_3B: + // это перед пассивацией, требует свободную промывку 4А и на всякий случай свободную пассивацию + if (!zone_is_busy(ZONE_PASSIVATION) && !zone_is_busy(ZONE_WASHING_4A)) { + return ZONE_PASSIVATION; } // это атомарная операция, по идее вносить барабан в пассивацию нельзя break; - case PROCESS_PASSIVATION: - // процесс пассивации, нужна промывка 4B (зона 21) (потому что сейчас я в 4A) - if (!zone_is_busy(21)) { - return 21; + + case ZONE_PASSIVATION: + // процесс пассивации, нужна промывка 4A + // чисто теоретически сюда никогда не попадем, но если вдруг выстрелит пусть будет + if (!zone_is_busy(ZONE_WASHING_4A)) { + return ZONE_WASHING_4A; } break; - case PROCESS_WASHING_4B: - // процесс пассивации, нужна промывка 4B (зона 21) (потому что сейчас я в 4A) - if (!zone_is_busy(22)) { - return 22; + + case ZONE_WASHING_4A: + // промывка 4А, перекладываем в промывку 4Б + if (!zone_is_busy(ZONE_WASHING_4B)) { + return ZONE_WASHING_4B; } break; - case PROCESS_RETURN_1: + + case ZONE_WASHING_4B: + // процесс пассивации, нужна промывка 4B (зона 21) (потому что сейчас я в 4A) + if (!zone_is_busy(ZONE_UNLOAD)) { + return ZONE_UNLOAD; + } + break; + + case ZONE_UNLOAD: // последняя промывка, нужно разрешение на выгрузку - if (schedulerUnloadButton) { - // нужно промывку 3б (зона 10) и загрузку 0 - if (!zone_is_busy(17) || !zone_is_busy(0)) { + if (schedulerOneRobotMode) { + // нужно промывку загрузку 0 + if (!zone_is_busy(17)) { return 17; } } - break; - case PROCESS_RETURN_2: - if (schedulerOneRobotMode) { - if (!schedulerUnloadButton) { - break; - } - } - - // нужна свободная выгрузка - if (!zone_is_busy(0)) { - return 0; - } - break; } return -1; @@ -184,13 +191,12 @@ short get_operation_priority(short barrel_id) { } -struct barrel makeBarrel(short flags, short zone, short timer, short process) { +struct barrel makeBarrel(short flags, short zone, short timer) { struct barrel b; b.flags.raw_word = flags; b.zone = zone; b.software_timer = timer; - b.curr_process = process; - b.time_defatting = 12; + b.time_degreasing = 12; b.time_washing_1a = 4; b.time_washing_1b = 6; b.time_etching = 16; @@ -261,135 +267,236 @@ static short scheduler_find_task(struct scheduler_task* tasks, const short curr_ } -void schedule_robot_1() { - static short transaction_state = 0; +void debug_print_robot1_code() { +// printf("INFO: code length is %d\n", cmd_index); + printf("Code for R0, B%d:\n", robot1_code.barrel_id); + for (int i = 0; i < 16; i++) { + const short cmd_arg = robot1_code.code[i] & (~ROBOT_CMD_MASK); - // начало транзакции - - if (transaction_state == 0) { - // формируем список задач - 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); + if ((robot1_code.code[i] & ROBOT_CMD_MASK) == ROBOT_CMD_END) { + printf(" END\n"); + break; } - // найти подходящую задачу - if (schedulerOneRobotMode) { - short target_task = scheduler_find_task(tasks, robot1.dx.current_zone); - - if (target_task >= 0) { - // создаем транзакцию - if (tasks[target_task].dest_zone == -2) { - // пассивация - printf("Get work: passivate barrel %d\n", target_task); - robot1_cmd.cmd = 3; // пассивация - } else { - printf("Get work: move barrel %d from %d to %d\n", - target_task, tasks[target_task].start_zone, tasks[target_task].dest_zone); - robot1_cmd.cmd = 2; // везем барабан - robot1_cmd.args[0] = tasks[target_task].start_zone; - robot1_cmd.args[1] = tasks[target_task].dest_zone; - } -// barrels[target_barrel].zone = target_zone; - barrels[target_task].flags.robot = 1; - - // TODO сделать нормальное переключение зон с учетом тех, что можно отключить - // TODO добавить ограничение - нельзя отключить сразу все зоны цинкования или травления - if (tasks[target_task].dest_zone == 3 || tasks[target_task].dest_zone == 4) { - etching_zone ^= 0x1; // переключаем следующую зону - } - - if (tasks[target_task].dest_zone >= 9 && tasks[target_task].dest_zone <= 17) { - galvanizing_zone = (galvanizing_zone + 1) % 8; - } - - if (tasks[target_task].start_zone == 22) { - // выгрузка, снимаем кнопку выгрузки - schedulerUnloadButton = 0; - } - - transaction_state = 1; - } - } else { - printf("WARMING: support only one robot mode\n"); - } - } else if (transaction_state == 1) { - if (robot1_cmd.cmd == 0) { - transaction_state = 2; - } - } else { - // post transaction - short barrel = get_robot_barrel(1); - - struct barrel* b = &barrels[barrel]; - - if (barrel >= 0) { - b->flags.is_up = 0; - b->flags.robot = 0; - if (robot1_cmd.cmd == 2) { - b->zone = robot1_cmd.args[2]; - } else if (robot1_cmd.cmd == 3) { - b->zone = 20; - } - } - - switch (b->curr_process) { - // case curr: bar->curr_process = next; bar->software_timer = bar->time; break - - // после загрузки: ставим обезжиривание - case PROCESS_NONE: b->curr_process = PROCESS_DEFATTING; b->software_timer = b->time_defatting; break; - - // после обезжира: ставим промывку 1а - case PROCESS_DEFATTING: b->curr_process = PROCESS_WASHING_1A; b->software_timer = b->time_washing_1a; break; - - // после промывки 1а: ставим промывку 1б - case PROCESS_WASHING_1A: b->curr_process = PROCESS_WASHING_1B; b->software_timer = b->time_washing_1b; break; - - // после промывки 1а: ставим травление - case PROCESS_WASHING_1B: b->curr_process = PROCESS_ETCHING; b->software_timer = b->time_etching; break; - - // после травления: ставим промывку 2а - case PROCESS_ETCHING: b->curr_process = PROCESS_WASHING_2A; b->software_timer = b->time_washing_2a; break; - - // после промывки 2а: ставим промывку 2б - case PROCESS_WASHING_2A: b->curr_process = PROCESS_WASHING_2B; b->software_timer = b->time_washing_2b; break; - - // после промывки 2б: ставим цинкование - case PROCESS_WASHING_2B: b->curr_process = PROCESS_GALVANIZING; b->software_timer = b->time_galvanizing; break; - - // после цинкования: ставим промывку 3а - case PROCESS_GALVANIZING: b->curr_process = PROCESS_WASHING_3A; b->software_timer = b->time_washing_3a; break; - - // после промывки 3а: ставим промывку 1б - case PROCESS_WASHING_3A: b->curr_process = PROCESS_WASHING_3B; b->software_timer = b->time_washing_3b; break; - - // после промывки 3б: ставим пассивацию - case PROCESS_WASHING_3B: b->curr_process = PROCESS_PASSIVATION; break; - - // после пассивации, барабан в промывке 4а: ставим промывку 4б - case PROCESS_PASSIVATION: b->curr_process = PROCESS_WASHING_4B; b->software_timer = b->time_washing_4b; break; - - // после промывки 4б: дальше выгрузка - case PROCESS_WASHING_4B: - if (schedulerOneRobotMode) { - b->curr_process = PROCESS_RETURN_2; - } else { - b->curr_process = PROCESS_RETURN_1; - } - b->software_timer = 0; + switch (robot1_code.code[i] & ROBOT_CMD_MASK) { + case ROBOT_CMD_MOVE_TO_ZONE: + printf(" move to zone %d (with barrel: %d)\n", cmd_arg & (~ROBOT_WITH_BARREL), (cmd_arg & ROBOT_WITH_BARREL) != 0); break; - case PROCESS_RETURN_1: b->curr_process = PROCESS_RETURN_2; b->software_timer = 0; break; + case ROBOT_CMD_MOVE_OFF: + printf(" move to offset pos\n"); + break; + + case ROBOT_CMD_UP: + printf(" up (with barrel: %d)\n", (cmd_arg & ROBOT_WITH_BARREL) != 0); + break; + + // в эмуляторе не важно где я, поэтому тут обе команды вниз обрабатываются одинаково + case ROBOT_CMD_DOWN: + printf(" down (with barrel: %d)\n", (cmd_arg & ROBOT_WITH_BARREL) != 0); + break; + + case ROBOT_CMD_DOWN_2: + printf(" down 2 (with barrel: %d)\n", (cmd_arg & ROBOT_WITH_BARREL) != 0); + break; + + case ROBOT_CMD_WAIT: + printf(" wait %d secs\n", cmd_arg); + break; + + case ROBOT_CMD_TMR_SET: + printf(" set barrel timer %d secs\n", cmd_arg); + i++; + break; + + case ROBOT_CMD_SET_LOCK_ZONE: + printf(" set lock zone %d\n", cmd_arg); + break; + + case ROBOT_CMD_CORRECT_AXIS: + if (cmd_arg == ROBOT_AXIS_X) { + printf(" correct axis: X\n"); + } else if (cmd_arg == ROBOT_AXIS_Z) { + printf(" correct axis: Z\n"); + } else { + printf(" correct axis: INVALID (%d)\n", cmd_arg); + } + break; + + case ROBOT_CMD_INC_ZONE: + if (cmd_arg == ROBOT_ZONE_ETCH) { + printf(" increment: etching\n"); + } else if (cmd_arg == ROBOT_ZONE_GAL) { + printf(" increment: galvanic\n"); + } else { + printf(" increment: INVALID (%d)\n", cmd_arg); + } + break; - case PROCESS_RETURN_2: default: - b->flags.is_exist = 0; + printf(" UNKNOWN: 0x(%04X)\n", cmd_arg); } + } +} - transaction_state = 0; + +void schedule_robot_1() { + // формируем список задач + 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); + } + + // найти подходящую задачу + if (schedulerOneRobotMode) { + short target_task = scheduler_find_task(tasks, robot1.dx.current_zone); + + if (target_task >= 0) { + // создаем код транзакции, пока обычный + robot1_code.barrel_id = target_task; + short cmd_index = 0; + + // первым делом добавляем команду опустить траверсу + robot1_code.code[cmd_index++] = ROBOT_CMD_DOWN; + + if (tasks[target_task].start_zone != ZONE_WASHING_3B) { + if (robot1.dx.current_zone != tasks[target_task].start_zone) { + if (tasks[target_task].start_zone == 22) { + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_OFF; + robot1_code.code[cmd_index++] = ROBOT_CMD_UP; + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE | 21; + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_OFF; + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE | 22; + } else { + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE | tasks[target_task].start_zone; + } + } + + robot1_code.code[cmd_index++] = ROBOT_CMD_UP_WITH_BARREL; + + // теперь надо определиться с тем, сколько ждать скапывания + switch (tasks[target_task].start_zone) { + case ZONE_DEGREASING: + case ZONE_ETCHING_1: + case ZONE_ETCHING_2: + 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: + // время скапывания реактивов + // TODO добавить переменные времен скапывания + robot1_code.code[cmd_index++] = ROBOT_CMD_WAIT | 30; + break; + + case ZONE_WASHING_1A: + case ZONE_WASHING_2A: + case ZONE_WASHING_3A: + case ZONE_WASHING_4A: + // время скапывания 1-го каскада промывок + robot1_code.code[cmd_index++] = ROBOT_CMD_WAIT | 3; + break; + + case ZONE_WASHING_1B: + case ZONE_WASHING_2B: + case ZONE_WASHING_3B: + case ZONE_WASHING_4B: + // время скапывания 2-го каскада промывок + robot1_code.code[cmd_index++] = ROBOT_CMD_WAIT | 20; + break; + } + + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE_WITH_BARREL | tasks[target_task].dest_zone; + + if (tasks[target_task].dest_zone == 22) { + robot1_code.code[cmd_index++] = ROBOT_CMD_DOWN_2_WITH_BARREL; + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE | 21; + // NOTE старая механика не позволяет просто опустить траверсу до конца, для новой изменить поведение + robot1_code.code[cmd_index++] = ROBOT_CMD_UP; + robot1_code.code[cmd_index++] = ROBOT_CMD_DOWN; + } else { + robot1_code.code[cmd_index++] = ROBOT_CMD_DOWN_WITH_BARREL; + if (tasks[target_task].dest_zone != 0) { + // установка времени ожидания барабана + short tmp = -1; + switch (tasks[target_task].dest_zone) { + case ZONE_DEGREASING: + tmp = barrels[target_task].time_degreasing; break; + + case ZONE_ETCHING_1: + case ZONE_ETCHING_2: + tmp = barrels[target_task].time_etching; 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: + tmp = barrels[target_task].time_galvanizing; break; + + case ZONE_WASHING_1A: + tmp = barrels[target_task].time_washing_1a; break; + case ZONE_WASHING_2A: + tmp = barrels[target_task].time_washing_2a; break; + case ZONE_WASHING_3A: + tmp = barrels[target_task].time_washing_3a; break; + case ZONE_WASHING_4A: + tmp = barrels[target_task].time_washing_4a; break; + + case ZONE_WASHING_1B: + tmp = barrels[target_task].time_washing_1b; break; + case ZONE_WASHING_2B: + tmp = barrels[target_task].time_washing_2b; break; + case ZONE_WASHING_3B: + tmp = barrels[target_task].time_washing_3b; break; + case ZONE_WASHING_4B: + tmp = barrels[target_task].time_washing_4b; break; + } + + if (tmp != -1) { + robot1_code.code[cmd_index++] = ROBOT_CMD_TMR_SET; + robot1_code.code[cmd_index++] = tmp; + } + } + } + } else { + // пассивация, тут все просто + if (robot1.dx.current_zone != tasks[target_task].start_zone) { + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE | ZONE_WASHING_3B; + } + + robot1_code.code[cmd_index++] = ROBOT_CMD_UP_WITH_BARREL; + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE_WITH_BARREL | ZONE_PASSIVATION; + robot1_code.code[cmd_index++] = ROBOT_CMD_DOWN_WITH_BARREL; + + robot1_code.code[cmd_index++] = ROBOT_CMD_TMR_SET; + robot1_code.code[cmd_index++] = barrels[target_task].time_passivation; + + robot1_code.code[cmd_index++] = ROBOT_CMD_UP_WITH_BARREL; + robot1_code.code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE_WITH_BARREL | ZONE_WASHING_4A; + robot1_code.code[cmd_index++] = ROBOT_CMD_DOWN_WITH_BARREL; + + robot1_code.code[cmd_index++] = ROBOT_CMD_TMR_SET; + robot1_code.code[cmd_index++] = barrels[target_task].time_washing_4a; + } + + robot1_code.code[cmd_index++] = ROBOT_CMD_END; + robot1_code.PC = 0; + + printf("INFO: code length is %d\n", cmd_index); + debug_print_robot1_code(); + } + } else { + printf("WARMING: support only one robot mode\n"); } } @@ -397,7 +504,7 @@ void schedule_robot_1() { char create_barrel_in_load(short zone) { for (int i = 0; i < BARRELS_COUNT; i++) { if (!barrels[i].flags.is_exist) { - barrels[i] = makeBarrel(1, zone, 0, PROCESS_NONE); + barrels[i] = makeBarrel(1, zone, 0); return 0; } } @@ -419,30 +526,30 @@ char create_barrel_in_load(short zone) { * съебать в 22 зону иначе * съебать в зону изъятия - * поднять траверсу - если зона изъятия != 22 и зона изъятия != 0: + * поднять траверсу с барабаном + если зона изъятия != 22 и зона изъятия != 1: * ждать скапывания (зависит от зоны) * ехать в зону назначения если зона назначения == 22 - * опустить траверсу не до конца + * опустить траверсу не до конца с барабаном * съебать в 21 зону если ЭНКОДЕРЫ СТАРЫЕ (по умолчанию) * поднять траверсу * опустить траверсу иначе - * опустить траверсу - если зона назначения != 1 + * опустить траверсу с барабаном + если зона назначения != 0 * установить время ожидания барабана (зависит от зоны) иначе если текущая зона != промывка 3б * съебать в промывку 3б - * поднять траверсу + * поднять траверсу с барабаном * съебать в пассивацию - * опустить траверсу + * опустить траверсу с барабаном * поставить время ожидания барабана в <время пассивации> - * поднять траверсу + * поднять траверсу с барабаном * съебать в зону промывка 4а - * опустить траверсу + * опустить траверсу с барабаном * установить время ожидания барабана (для промывки 4а) */ @@ -465,7 +572,7 @@ void scheduler_main() { } } } - if (robot1_cmd.cmd == 0) { + if (robot1_code.PC < 0) { schedule_robot_1(); } diff --git a/utils.c b/utils.c index 9b754de..8a52049 100644 --- a/utils.c +++ b/utils.c @@ -2,5 +2,3 @@ struct barrel barrels[BARRELS_COUNT]; -struct robot_cmd robot1_cmd; -struct robot_cmd robot2_cmd; diff --git a/utils.h b/utils.h index 68723a9..0cff38d 100644 --- a/utils.h +++ b/utils.h @@ -49,10 +49,9 @@ struct barrel { short zone; // программный таймер, тикает сразу у всех барабанов, short software_timer; - short curr_process; // стадия процесса // время процессов - short time_defatting; // Время обезжиривания + short time_degreasing; // Время обезжиривания short time_washing_1a; // Время промывки 1А short time_washing_1b; // Время промывки 1Б short time_etching; // Время травления @@ -66,30 +65,6 @@ struct barrel { short time_washing_4b; // Время промывки 4Б }; -// deprecated: do not use! -enum BarrelProcess { - PROCESS_NONE = 0, // сразу после загрузки - PROCESS_DEFATTING, // обезжиривание - PROCESS_WASHING_1A, // промывка 1А - PROCESS_WASHING_1B, // промывка 1Б - PROCESS_ETCHING, // травление - PROCESS_WASHING_2A, // промывка 2А - PROCESS_WASHING_2B, // промывка 2Б - PROCESS_GALVANIZING, // цинкование - PROCESS_WASHING_3A, // промывка 3А - PROCESS_WASHING_3B, // промывка 3Б - PROCESS_PASSIVATION, // пассивация - PROCESS_WASHING_4B, // промывка 4Б - PROCESS_RETURN_1, // возвращение обратно, стадия 1 - перекладываем в свободную промывку (если есть) - PROCESS_RETURN_2, // возвращение обратно, стадия 2 - перекладываем в свободную загрузку и удалить барабан -}; - -struct robot_cmd { - short cmd; - short args[2]; - short step; -}; - union robot_regs_mx { short raw_word; @@ -159,8 +134,6 @@ extern "C" { extern struct barrel barrels[BARRELS_COUNT]; -extern struct robot_cmd robot1_cmd; -extern struct robot_cmd robot2_cmd; // почему-то компилер говорит что размер структуру сраный //extern struct robot robot1; @@ -176,9 +149,28 @@ extern struct robot_cmd robot2_cmd; #define ROBOT_CMD_WAIT 0x6000 #define ROBOT_CMD_TMR_SET 0x7000 #define ROBOT_CMD_SET_LOCK_ZONE 0x8000 -#define ROBOT_CMD_CORRECT_X 0x9000 -#define ROBOT_CMD_CORRECT_Z 0xA000 +#define ROBOT_CMD_CORRECT_AXIS 0x9000 +#define ROBOT_CMD_INC_ZONE 0xA000 +// перемещение с барабаном +#define ROBOT_WITH_BARREL 0x0800 + +// алиасы перемещений с барабаном +#define ROBOT_CMD_MOVE_TO_ZONE_WITH_BARREL (ROBOT_CMD_MOVE_TO_ZONE | ROBOT_WITH_BARREL) +#define ROBOT_CMD_UP_WITH_BARREL (ROBOT_CMD_UP | ROBOT_WITH_BARREL) +#define ROBOT_CMD_DOWN_WITH_BARREL (ROBOT_CMD_DOWN | ROBOT_WITH_BARREL) +#define ROBOT_CMD_DOWN_2_WITH_BARREL (ROBOT_CMD_DOWN_2 | ROBOT_WITH_BARREL) + + +#define ROBOT_AXIS_X 1 +#define ROBOT_CMD_CORRECT_AXIS_X (ROBOT_CMD_CORRECT_AXIS | ROBOT_AXIS_X) +#define ROBOT_AXIS_Z 2 +#define ROBOT_CMD_CORRECT_AXIS_Z (ROBOT_CMD_CORRECT_AXIS | ROBOT_AXIS_Z) + +#define ROBOT_ZONE_ETCH 1 +#define ROBOT_CMD_INC_ZONE_ETCH (ROBOT_CMD_INC_ZONE | ROBOT_ZONE_ETCH) +#define ROBOT_ZONE_GAL 2 +#define ROBOT_CMD_INC_ZONE_GAL (ROBOT_CMD_INC_ZONE | ROBOT_ZONE_GAL) // NOTE первой командой на любую транзакцию должна стоять команда опустить траверсу (в 22 зоне по идее никогда не закончим) struct robot_code { @@ -188,16 +180,16 @@ struct robot_code { /* * система команд, которая нужна: (квадратные скобки - аргумент это младший байт, фигурные - отдельное слово) * 0: конец - * 1 [зона]: съебаться в зону + * 1 (опция с барабаном) [зона]: съебаться в зону * 2: встать на смещенную позицию - * 3 [с барабаном]: поднять траверсу (перед выполнением ожидать если таймер барабана не истек) - * 4 [с барабаном]: опустить траверсу - * 5 [с барабаном]: опустить траверсу не до конца + * 3 (опция с барабаном): поднять траверсу (перед выполнением ожидать если таймер барабана не истек) + * 4 (опция с барабаном): опустить траверсу + * 5 (опция с барабаном): опустить траверсу не до конца * 6 [сек]: пауза на нужное количество секунд * 7 {время}: установить таймер барабану * 8 [зона]: установить зону блокировки - * 9: скорректировать ос X - * 10: скорректировать ос Z + * 9 [X(1) | Y(2)]: скорректировать ось + * 10 [ETCH(1) |GAL (2)]: сделать инкремент зоны гальваники или обезжиривания * * формат команды: (команда, старший байт) [младший байт, аргумент команды (если есть)] [слово, аргумент если команда требует] */