703 lines
28 KiB
C
703 lines
28 KiB
C
#ifdef EMULATOR
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include "emulator.h"
|
||
short etching_zone = 0, galvanizing_zone = 0;
|
||
#endif
|
||
|
||
|
||
char zone_is_busy(short zone) {
|
||
for (short i = 0; i < 10; i++) {
|
||
if (barrels[i].flags.is_exist && barrels[i].zone == zone) {
|
||
return 1;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static short get_robot_barrel(char robot_id) {
|
||
for (short i = 0; i < BARRELS_COUNT; i++) {
|
||
if (barrels[i].flags.robot == robot_id) {
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
// TODO обновить метод для работы с двумя роботами
|
||
// вернет можно ли ехать и главное куда ехать, если можно (нельзя если вернулось значение < 0)
|
||
// -1 вернет что перемещать нельзя
|
||
// -2 вернет если требуется атомарная операция пассивации
|
||
short can_move(struct barrel* bar) {
|
||
// сразу отсекаем варианты, при которых невозможно переместить барабан
|
||
if (!bar->flags.is_exist) {
|
||
return -1;
|
||
}
|
||
|
||
if (bar->software_timer > 0) {
|
||
return -1;
|
||
}
|
||
|
||
if (bar->flags.robot != 0) {
|
||
return -2;
|
||
}
|
||
|
||
#ifdef EMULATOR
|
||
if (!schedulerOneRobotMode) {
|
||
printf("WARMING: нет проверки того, что для перемещения барабана не мешает второй робот\n");
|
||
}
|
||
#endif
|
||
|
||
// дальше нужно проверить, что можно передвигать бочку
|
||
|
||
switch (bar->zone) {
|
||
case ZONE_LOAD_2:
|
||
// загрузка 2, только в нее можно грузить новые барабаны, нужно обезжиривание
|
||
if (!zone_is_busy(ZONE_DEGREASING)) {
|
||
return ZONE_DEGREASING;
|
||
}
|
||
break;
|
||
|
||
case ZONE_DEGREASING:
|
||
// обезжиривание, нужна промывка 1А
|
||
if (!zone_is_busy(ZONE_WASHING_1A)) {
|
||
return ZONE_WASHING_1A;
|
||
}
|
||
break;
|
||
|
||
case ZONE_WASHING_1A:
|
||
// промывка 1А, нужна промывка 1Б
|
||
if (!zone_is_busy(ZONE_WASHING_1B)) {
|
||
return ZONE_WASHING_1B;
|
||
}
|
||
break;
|
||
|
||
case ZONE_WASHING_1B:
|
||
// промывка 1Б, нужно травление (зоны 5-6)
|
||
if (!zone_is_busy(ZONE_ETCHING_1 + etching_zone)) {
|
||
return ZONE_ETCHING_1 + etching_zone;
|
||
}
|
||
break;
|
||
|
||
case ZONE_ETCHING_1:
|
||
case ZONE_ETCHING_2:
|
||
// травление, нужна промывка 2А
|
||
if (!zone_is_busy(ZONE_WASHING_2A)) {
|
||
return ZONE_WASHING_2A;
|
||
}
|
||
break;
|
||
|
||
case ZONE_WASHING_2A:
|
||
// промывка 2А, нужна промывка 2Б
|
||
if (!zone_is_busy(ZONE_WASHING_2B)) {
|
||
return ZONE_WASHING_2B;
|
||
}
|
||
break;
|
||
|
||
case ZONE_WASHING_2B:
|
||
// промывка 2Б, нужно цинкование (зоны 9-16)
|
||
if (!zone_is_busy(ZONE_GALVANIZING_1 + galvanizing_zone)) {
|
||
return 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 <= ZONE_UNLOAD; i++) {
|
||
if (zone_is_busy(i)) {
|
||
count++;
|
||
}
|
||
}
|
||
if (count < 3) {
|
||
return ZONE_WASHING_3A;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case ZONE_WASHING_3A:
|
||
// промывка 3А, перекладываем в промывку 3Б
|
||
if (!zone_is_busy(ZONE_WASHING_3B)) {
|
||
return ZONE_WASHING_3B;
|
||
}
|
||
break;
|
||
|
||
case ZONE_WASHING_3B:
|
||
// это перед пассивацией, требует свободную промывку 4А и на всякий случай свободную пассивацию
|
||
if (!zone_is_busy(ZONE_PASSIVATION) && !zone_is_busy(ZONE_WASHING_4A)) {
|
||
return ZONE_PASSIVATION;
|
||
}
|
||
// это атомарная операция, по идее вносить барабан в пассивацию нельзя
|
||
break;
|
||
|
||
case ZONE_PASSIVATION:
|
||
// процесс пассивации, нужна промывка 4A
|
||
// чисто теоретически сюда никогда не попадем, но если вдруг выстрелит пусть будет
|
||
if (!zone_is_busy(ZONE_WASHING_4A)) {
|
||
return ZONE_WASHING_4A;
|
||
}
|
||
break;
|
||
|
||
case ZONE_WASHING_4A:
|
||
// промывка 4А, перекладываем в промывку 4Б
|
||
if (!zone_is_busy(ZONE_WASHING_4B)) {
|
||
return ZONE_WASHING_4B;
|
||
}
|
||
break;
|
||
|
||
case ZONE_WASHING_4B:
|
||
// процесс пассивации, нужна промывка 4B (зона 21) (потому что сейчас я в 4A)
|
||
if (!zone_is_busy(ZONE_UNLOAD)) {
|
||
return ZONE_UNLOAD;
|
||
}
|
||
break;
|
||
|
||
case ZONE_UNLOAD:
|
||
// последняя промывка, нужно разрешение на выгрузку
|
||
if (schedulerOneRobotMode && button_unload) {
|
||
// нужно промывку загрузку 0
|
||
if (!zone_is_busy(ZONE_LOAD_1)) {
|
||
return ZONE_LOAD_1;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
|
||
struct scheduler_task {
|
||
short start_zone; // стартовая зона
|
||
short dest_zone; // конечная зона
|
||
short priority; // приоритет, чем больше тем выше, по умолчанию 0
|
||
};
|
||
|
||
// выставляет приоритет операции (зависит только от зоны, в которой робот находится)
|
||
short get_operation_priority(short barrel_id) {
|
||
// сделать приоритет на барабан, который больше всего ждет
|
||
if (barrels[barrel_id].zone >= ZONE_GALVANIZING_1 && barrels[barrel_id].zone <= ZONE_GALVANIZING_8) {
|
||
// теперь надо выяснить, есть ли барабаны с большим временем ожидания
|
||
// тут возможны несколько случаев:
|
||
// 1) когда барабан один такой (больше в цинковании нет барабанов чтобы их изъять),
|
||
// 2) когда барабанов несколько, соотвественно если есть барабан с наибольшим временем, то надо ему дать приоритет 1, а остальным 0,
|
||
//
|
||
|
||
char is_not_one = 0;
|
||
char is_with_max_time = 1;
|
||
|
||
for (short i = 0; i < BARRELS_COUNT; i++) {
|
||
if (i == barrel_id) {
|
||
continue;
|
||
}
|
||
if (barrels[i].flags.is_exist && barrels[i].zone >= ZONE_GALVANIZING_1 && barrels[i].zone <= ZONE_GALVANIZING_8) {
|
||
if (can_move(barrels + i) >= 0) {
|
||
is_not_one = 1;
|
||
if (barrels[i].software_timer > barrels[barrel_id].software_timer) {
|
||
is_with_max_time = 0;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (is_not_one == 0) {
|
||
return 1;
|
||
}
|
||
return is_with_max_time;
|
||
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
// теперь то же самое, только для травления (только тут задача проще потому что травления всего 2 зоны, и надо только один барабан если он есть)
|
||
if (barrels[barrel_id].zone >= ZONE_ETCHING_1 && barrels[barrel_id].zone <= ZONE_ETCHING_2) {
|
||
|
||
for (short i = 0; i < BARRELS_COUNT; i++) {
|
||
if (i == barrel_id) {
|
||
continue;
|
||
}
|
||
|
||
if (barrels[i].flags.is_exist && barrels[i].zone >= ZONE_ETCHING_1 && barrels[i].zone <= ZONE_ETCHING_2) {
|
||
if (can_move(barrels + i) >= 0) {
|
||
if (barrels[i].software_timer > barrels[barrel_id].software_timer) {
|
||
return 0; // у этого барабана меньше время операции, так что приоритет ему 0
|
||
} else {
|
||
return 1; // поскольку у нашего барабана максимальное время ожидания
|
||
}
|
||
}
|
||
}
|
||
// барабан не найден, приоритет ему 1
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
// task->priority = 0;
|
||
// switch (barrel_process) {
|
||
// case PROCESS_RETURN_2:
|
||
// break;
|
||
// }
|
||
|
||
return 1; // 1 - нормальный приоритет
|
||
}
|
||
|
||
|
||
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.time_degreasing = 12;
|
||
b.time_washing_1a = 4;
|
||
b.time_washing_1b = 6;
|
||
b.time_etching = 25;
|
||
b.time_washing_2a = 6;
|
||
b.time_washing_2b = 8;
|
||
b.time_galvanizing = 60;
|
||
b.time_washing_3a = 8;
|
||
b.time_washing_3b = 10;
|
||
b.time_passivation = 3;
|
||
b.time_washing_4a = 12;
|
||
b.time_washing_4b = 14;
|
||
return b;
|
||
}
|
||
|
||
|
||
static short scheduler_find_task(struct scheduler_task* tasks, const short curr_pos) {
|
||
// TODO добавить поддержку ночного режима и режима двух роботов
|
||
// для начала надо найти максимальный приоритет у операций
|
||
short max_priority = -1;
|
||
for (short i = 0; i < BARRELS_COUNT; i++) {
|
||
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 == -2) {
|
||
target = 18;
|
||
} else 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;
|
||
}
|
||
}
|
||
} else {
|
||
// таск слева, ищем максимально дальний (с минимальной зоной)
|
||
if (left == -1) {
|
||
left = i;
|
||
} else {
|
||
if (barrels[left].zone > target) {
|
||
left = i;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// итого есть результат: есть ли таски, которые надо тащить вперед (и если надо то какой ближний), и есть первый таск
|
||
if (left < 0) {
|
||
return right; // вернем таск справа (если его нет, в переменной будет -1)
|
||
}
|
||
if (right < 0) {
|
||
return left; // если вдруг задачи справа не оказалось, вернем задачу слева если есть
|
||
}
|
||
|
||
// вычисляем что ближе
|
||
short ld = curr_pos - left; // левая дельта
|
||
short rd = right - curr_pos; // правая дельта
|
||
|
||
// дальше сравниваем дельты
|
||
// по идее если они равны то с бОльшим приоритетом робот поедет в левую часть
|
||
// а левую дельту вообще уменьшу на 1, чтобы цель слева казалась ближе
|
||
if (rd > ld - 1) {
|
||
return left;
|
||
} else {
|
||
return right;
|
||
}
|
||
}
|
||
|
||
#ifdef EMULATOR
|
||
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 = (short)(robot1_code.code[i] & (short)(~ROBOT_CMD_MASK));
|
||
|
||
printf(" %3d 0x%04X", i, robot1_code.code[i] & 0xFFFF);
|
||
|
||
if ((robot1_code.code[i] & ROBOT_CMD_MASK) == ROBOT_CMD_END_code) {
|
||
printf(" END\n");
|
||
break;
|
||
}
|
||
|
||
switch ((short)(robot1_code.code[i] & (short)ROBOT_CMD_MASK)) {
|
||
case ROBOT_CMD_MOVE_TO_ZONE_code:
|
||
printf(" move to zone %d (with barrel: %d)\n", cmd_arg & (~ROBOT_WITH_BARREL), (cmd_arg & ROBOT_WITH_BARREL) != 0);
|
||
break;
|
||
|
||
case ROBOT_CMD_MOVE_OFF_code:
|
||
if (cmd_arg) {
|
||
printf(" move to offset pos\n");
|
||
} else {
|
||
printf(" move to accurate pos\n");
|
||
}
|
||
break;
|
||
|
||
case ROBOT_CMD_UP_code:
|
||
printf(" up (with barrel: %d)\n", (cmd_arg & ROBOT_WITH_BARREL) != 0);
|
||
break;
|
||
|
||
// в эмуляторе не важно где я, поэтому тут обе команды вниз обрабатываются одинаково
|
||
case ROBOT_CMD_DOWN_code:
|
||
printf(" down (with barrel: %d)\n", (cmd_arg & ROBOT_WITH_BARREL) != 0);
|
||
break;
|
||
|
||
case ROBOT_CMD_WAIT_code:
|
||
printf(" wait %d secs\n", cmd_arg);
|
||
break;
|
||
|
||
case ROBOT_CMD_TMR_SET_code:
|
||
printf(" set barrel timer %d secs\n", cmd_arg);
|
||
break;
|
||
|
||
case ROBOT_CMD_SET_LOCK_ZONE_code:
|
||
printf(" set lock zone %d\n", cmd_arg);
|
||
break;
|
||
|
||
case ROBOT_CMD_CORRECT_AXIS_code:
|
||
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_code:
|
||
if (cmd_arg == ROBOT_ZONE_GAL) {
|
||
printf(" increment zone: galvanic\n");
|
||
} else if (cmd_arg == ROBOT_ZONE_ETCH) {
|
||
printf(" increment zone: etching\n");
|
||
} else {
|
||
printf(" increment zone: INVALID (0x%4X)\n", cmd_arg);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
printf(" UNKNOWN: 0x%04X\n", robot1_code.code[i] & 0xFFFF);
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
|
||
void create_operation(const short target_task, const struct scheduler_task* tasks, struct robot_code* code, const short current_zone) {
|
||
// создаем код транзакции, пока обычный
|
||
code->barrel_id = target_task;
|
||
short cmd_index = 0;
|
||
|
||
// первым делом добавляем команду опустить траверсу
|
||
code->code[cmd_index++] = ROBOT_CMD_DOWN();
|
||
|
||
if (tasks[target_task].dest_zone == ZONE_PASSIVATION) {
|
||
// пассивация, тут все просто
|
||
if (current_zone != tasks[target_task].start_zone) {
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(ZONE_WASHING_3B);
|
||
}
|
||
|
||
code->code[cmd_index++] = ROBOT_CMD_UP_WITH_BARREL();
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE_WITH_BARREL(ZONE_PASSIVATION);
|
||
code->code[cmd_index++] = ROBOT_CMD_DOWN_WITH_BARREL();
|
||
|
||
code->code[cmd_index++] = ROBOT_CMD_TMR_SET(barrels[target_task].time_passivation);
|
||
|
||
code->code[cmd_index++] = ROBOT_CMD_UP_WITH_BARREL();
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE_WITH_BARREL(ZONE_WASHING_4A);
|
||
code->code[cmd_index++] = ROBOT_CMD_DOWN_WITH_BARREL();
|
||
|
||
code->code[cmd_index++] = ROBOT_CMD_TMR_SET(barrels[target_task].time_washing_4a);
|
||
} else {
|
||
// любой другой случай
|
||
if (current_zone != tasks[target_task].start_zone) {
|
||
if (tasks[target_task].start_zone != 22) {
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(tasks[target_task].start_zone);
|
||
} else {
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_OFF();
|
||
code->code[cmd_index++] = ROBOT_CMD_UP();
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(22);
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_OFF();
|
||
code->code[cmd_index++] = ROBOT_CMD_DOWN();
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_ACCURATE();
|
||
}
|
||
}
|
||
|
||
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 добавить переменные времен скапывания
|
||
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-го каскада промывок
|
||
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-го каскада промывок
|
||
code->code[cmd_index++] = ROBOT_CMD_WAIT(20);
|
||
break;
|
||
}
|
||
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE_WITH_BARREL(tasks[target_task].dest_zone);
|
||
|
||
// инкремент зоны (если травление или цинкование)
|
||
if (tasks[target_task].dest_zone == ZONE_ETCHING_1 || tasks[target_task].dest_zone == ZONE_ETCHING_2) {
|
||
code->code[cmd_index++] = ROBOT_CMD_INC_ZONE(ROBOT_ZONE_ETCH);
|
||
} else if (tasks[target_task].dest_zone >= ZONE_GALVANIZING_1 && tasks[target_task].dest_zone <= ZONE_GALVANIZING_8) {
|
||
code->code[cmd_index++] = ROBOT_CMD_INC_ZONE(ROBOT_ZONE_GAL);
|
||
}
|
||
|
||
code->code[cmd_index++] = ROBOT_CMD_DOWN_WITH_BARREL();
|
||
|
||
if (tasks[target_task].dest_zone == 22) {
|
||
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(21);
|
||
// NOTE старая механика не позволяет просто опустить траверсу до конца, для новой изменить поведение
|
||
code->code[cmd_index++] = ROBOT_CMD_UP();
|
||
code->code[cmd_index++] = ROBOT_CMD_DOWN();
|
||
} else {
|
||
|
||
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 > 0) {
|
||
if (tmp > 8000) {
|
||
tmp = 8000;
|
||
}
|
||
code->code[cmd_index++] = ROBOT_CMD_TMR_SET(tmp);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
code->code[cmd_index++] = ROBOT_CMD_END();
|
||
code->PC = 0;
|
||
|
||
#ifdef EMULATOR
|
||
printf("INFO: code length is %d\n", cmd_index);
|
||
#endif
|
||
}
|
||
|
||
|
||
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 (tasks[i].dest_zone >= 0) {
|
||
tasks[i].priority = get_operation_priority(i);
|
||
}
|
||
}
|
||
|
||
// TODO добавить вставку lock-point'ов на задачах на несколько роботов
|
||
|
||
// найти подходящую задачу
|
||
if (schedulerOneRobotMode) {
|
||
short target_task = scheduler_find_task(tasks, robot1.dx.current_zone);
|
||
|
||
if (target_task >= 0) {
|
||
create_operation(target_task, tasks, &robot1_code, robot1.dx.current_zone);
|
||
|
||
#ifdef EMULATOR
|
||
debug_print_robot1_code();
|
||
#endif
|
||
}
|
||
} else {
|
||
printf("WARMING: support only one robot mode\n");
|
||
}
|
||
}
|
||
|
||
// вернет false если удалось вставить барабан, иначе true
|
||
char create_barrel_in_load() {
|
||
if (!zone_is_busy(1)) {
|
||
for (int i = 0; i < BARRELS_COUNT; i++) {
|
||
if (!barrels[i].flags.is_exist) {
|
||
barrels[i] = makeBarrel(1, 1, 0);
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
/*
|
||
=== ЦИКЛОГРАММА ПЕРЕТАСКИВАНИЯ БАРАБАНА ===
|
||
// NOTE первой командой на любую транзакцию должна стоять команда опустить траверсу (в 22 зоне мы никогда не закончим, за нее не беспокоится)
|
||
* опустить траверсу
|
||
если зона изъятия != промывка 3б
|
||
если текущая зона != зона иъятия
|
||
если зона изъятия == 22
|
||
* встать на смещенную
|
||
* поднять траверсу
|
||
* съебать в 21 зону
|
||
* встать на смещенную
|
||
* опустить траверсу не до конца
|
||
* съебать в 22 зону
|
||
иначе
|
||
* съебать в зону изъятия
|
||
* поднять траверсу с барабаном
|
||
если зона изъятия != 22 и зона изъятия != 1:
|
||
* ждать скапывания (зависит от зоны)
|
||
* ехать в зону назначения
|
||
если зона назначения == 22
|
||
* опустить траверсу не до конца с барабаном
|
||
* съебать в 21 зону
|
||
если ЭНКОДЕРЫ СТАРЫЕ (по умолчанию)
|
||
* поднять траверсу
|
||
* опустить траверсу
|
||
иначе
|
||
* опустить траверсу с барабаном
|
||
если зона назначения != 0
|
||
* установить время ожидания барабана (зависит от зоны)
|
||
иначе
|
||
если текущая зона != промывка 3б
|
||
* съебать в промывку 3б
|
||
* поднять траверсу с барабаном
|
||
* съебать в пассивацию
|
||
* опустить траверсу с барабаном
|
||
* поставить время ожидания барабана в <время пассивации>
|
||
* поднять траверсу с барабаном
|
||
* съебать в зону промывка 4а
|
||
* опустить траверсу с барабаном
|
||
* установить время ожидания барабана (для промывки 4а)
|
||
*/
|
||
|
||
void scheduler_main() {
|
||
// тут должно быть удаление барабана из зоны 1, если он там есть
|
||
// if (schedulerLoadButton1) {
|
||
// schedulerLoadButton1 = create_barrel_in_load(0);
|
||
// }
|
||
|
||
// тут возможна только вставка барабанов
|
||
if (button_load) {
|
||
button_load = create_barrel_in_load();
|
||
}
|
||
|
||
if (schedulerSoftwareTimer) {
|
||
schedulerSoftwareTimer = 0;
|
||
for (int i = 0; i < 10; i++) {
|
||
if (barrels[i].software_timer > -9999) {
|
||
barrels[i].software_timer--;
|
||
}
|
||
}
|
||
}
|
||
if (robot1_code.PC < 0) {
|
||
schedule_robot_1();
|
||
}
|
||
|
||
// пока без второго робота
|
||
// if (robot2_cmd.cmd == 0) {
|
||
// robot2_cmd.cmd = 2; // пиздуем в зону
|
||
// robot2_cmd.args[0] = rand() % 23;
|
||
// }
|
||
}
|