485 lines
15 KiB
C++
485 lines
15 KiB
C++
//
|
||
// Created by Владислав Остапов on 27.10.2022.
|
||
//
|
||
|
||
#include <cstring>
|
||
#include <iostream>
|
||
#include <libc.h>
|
||
#include <netinet/tcp.h>
|
||
#include "emulator.h"
|
||
#include "robot.h"
|
||
|
||
|
||
// закомментить когда надо будет отключить
|
||
//#define DEBUG_CORRECTION
|
||
|
||
|
||
struct barrel barrels[BARRELS_COUNT];
|
||
|
||
struct robot_regs robot1;
|
||
struct robot_regs robot2;
|
||
|
||
char _scheduler_software_timer = 0;
|
||
short scheduler_correction_stage = 0;
|
||
|
||
// кнопка загрузки в зоне 0, означает что барабан надо изъять из этой загрузки (а перед этим создать)
|
||
char button_load = 0;
|
||
char button_unload = 0;
|
||
char button_unload_end = 0;
|
||
char button_unload_remove = 0;
|
||
|
||
// времена операций для барабанов, устанавливается индивидуально каждому барабану
|
||
short hla_time_degreasing = 12;
|
||
short hla_time_washing_1a = 4;
|
||
short hla_time_washing_1b = 6;
|
||
short hla_time_etching = 25;
|
||
short hla_time_washing_2a = 6;
|
||
short hla_time_washing_2b = 8;
|
||
short hla_time_galvanizing = 60;
|
||
short hla_time_washing_3a = 8;
|
||
short hla_time_washing_3b = 10;
|
||
short hla_time_passivation = 3;
|
||
short hla_time_washing_4a = 12;
|
||
short hla_time_washing_4b = 14;
|
||
|
||
// времена скапывания, одинаковые для всех барабанов
|
||
short hla_time_digging = 8;
|
||
short hla_time_reagent = 30;
|
||
short hla_time_washing_1 = 3;
|
||
short hla_time_washing_2 = 20;
|
||
|
||
|
||
char hla_robot1_en = 1;
|
||
char hla_robot2_en = 1;
|
||
char one_robot_mode = (char)(hla_robot1_en ^ hla_robot2_en);
|
||
char scheduler_en = 1;
|
||
char scheduler_start_signal = 1;
|
||
char auto_mode_pause = 0;
|
||
char hla_night_mode = 0;
|
||
|
||
short hla_exchange_zone = ZONE_GALVANIZING_1;
|
||
|
||
short hla_disabled_zones = 0;
|
||
|
||
|
||
short etching_zone = -2, galvanizing_zone = -2;
|
||
|
||
char hla_correct_command = 0;
|
||
|
||
|
||
static const int ROWS = 10;
|
||
static const int COLS = 23 * 5 + 1;
|
||
static char buffer[ROWS][COLS];
|
||
static int current_tic = 0;
|
||
|
||
robot_code robot1_code{0, -1};
|
||
robot_code robot2_code{0, -1};
|
||
|
||
short robot1_lock_zone = 0;
|
||
short robot2_lock_zone = 0;
|
||
|
||
|
||
static int sock_fd;
|
||
static void send_str(const char* str) {
|
||
write(sock_fd, str, strlen(str));
|
||
}
|
||
|
||
static void image_init() {
|
||
// заполнение всего поля пробелами
|
||
memset(buffer, ' ', sizeof(buffer));
|
||
}
|
||
|
||
static void image_insert_sprite(int row, int col, const char* str, bool alpha = true) {
|
||
for (; row < ROWS; row++) {
|
||
for (int curr_col = col;; curr_col++) {
|
||
char src = *(str++);
|
||
|
||
// конец строки, заканчиваем рисовать
|
||
if (src == '\0') {
|
||
return;
|
||
}
|
||
|
||
// перевод строки, перевод на новую строку в этом спрайте
|
||
if (src == '\n') {
|
||
break;
|
||
}
|
||
|
||
// чтобы не рисовать мусор
|
||
if (src < ' ') {
|
||
src = ' ';
|
||
}
|
||
|
||
if (curr_col < COLS) {
|
||
// рисуем, остальные фрагменты будут отброшены
|
||
char frag = buffer[row][curr_col];
|
||
|
||
if (alpha) {
|
||
// этот режим позволяет пропускать изменение символа, если исходный символ пробел
|
||
if (src != ' ') {
|
||
frag = src;
|
||
}
|
||
} else {
|
||
frag = src;
|
||
}
|
||
|
||
buffer[row][curr_col] = frag;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static void image_draw_borders() {
|
||
// рамки ванн
|
||
// for (int i = 0; i < COLS; i += 5) {
|
||
// image_insert_sprite(5, i, "|\n|\n|");
|
||
// }
|
||
|
||
// рисование линий
|
||
for (int i = 0; i < ROWS - 1; i++) {
|
||
buffer[i][0] = '|';
|
||
buffer[i][COLS - 1] = '|';
|
||
}
|
||
memset(buffer[1], '=', sizeof(buffer[0]));
|
||
|
||
// рамки ванн
|
||
char tmp[24];
|
||
for (int i = 0, zone = 0; i < COLS; i += 5, zone++) {
|
||
const char* label = nullptr;
|
||
const char* disabled_label = "+XXXX+";
|
||
const char* selected_label = "+####+";
|
||
|
||
if (zone == ZONE_ETCHING_1) {
|
||
if (hla_disabled_zones & DISABLED_ETCH_1) {
|
||
label = disabled_label;
|
||
}
|
||
if (etching_zone == 0) {
|
||
label = selected_label;
|
||
}
|
||
}
|
||
|
||
if (zone == ZONE_ETCHING_2) {
|
||
if (hla_disabled_zones & DISABLED_ETCH_2) {
|
||
label = disabled_label;
|
||
}
|
||
if (etching_zone == 1) {
|
||
label = selected_label;
|
||
}
|
||
}
|
||
|
||
if (zone >= ZONE_GALVANIZING_1 && zone <= ZONE_GALVANIZING_8) {
|
||
const auto zone_id = zone - ZONE_GALVANIZING_1;
|
||
if (hla_disabled_zones & (DISABLED_GAL_1 << zone_id)) {
|
||
label = disabled_label;
|
||
}
|
||
if (galvanizing_zone == zone_id) {
|
||
label = selected_label;
|
||
}
|
||
}
|
||
|
||
if (label == nullptr) {
|
||
label = "+----+";
|
||
}
|
||
sprintf(tmp, "|\n|\n%s\n|\n|Z-%02d|", label, zone);
|
||
image_insert_sprite(5, i, tmp, false);
|
||
}
|
||
|
||
image_insert_sprite(8, 1, "LOAD LOAD DEFA W-1A W-1B ETCH ETCH W-2A W-2B "
|
||
" GAL GAL GAL GAL GAL GAL GAL GAL "
|
||
"W-3A W-3B PASS W-4A W-4B UNLD", true);
|
||
|
||
// счетчик тиков
|
||
sprintf(tmp, "tic: %d", current_tic);
|
||
image_insert_sprite(0, (int)(COLS - strlen(tmp) - 2), tmp, false);
|
||
}
|
||
|
||
|
||
static int barrels_count = 0, barrels_time = 0, max_time = 0;
|
||
|
||
static void collectBarrelsStatistic() {
|
||
barrels_time = 0;
|
||
barrels_count = 0;
|
||
|
||
for (int i = 0; i < BARRELS_COUNT; i++) {
|
||
if (barrels[i].flags.is_exist) {
|
||
barrels_count++;
|
||
if (barrels[i].zone <= ZONE_LOAD_2 || barrels[i].zone == ZONE_PASSIVATION || barrels[i].zone == ZONE_UNLOAD) {
|
||
continue;
|
||
}
|
||
if (barrels[i].flags.robot == 0 && barrels[i].software_timer < 0) {
|
||
// время отрицательное, вычитаем его чтобы убрать минус
|
||
barrels_time -= barrels[i].software_timer;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (max_time < barrels_time) {
|
||
max_time = barrels_time;
|
||
}
|
||
}
|
||
|
||
static void showAll() {
|
||
// 10 строк, 10*(\sb%1d\s) = 40
|
||
// барабан хочу показывать так
|
||
//
|
||
// # Bx | Bx | Bx
|
||
// #time|time|time
|
||
//
|
||
|
||
image_init();
|
||
image_draw_borders();
|
||
char tmp[64];
|
||
sprintf(tmp, "Lock1=%2d Lock2=%2d E=%d G=%d", robot1_lock_zone, robot2_lock_zone, etching_zone, galvanizing_zone);
|
||
image_insert_sprite(0, 2, tmp);
|
||
|
||
collectBarrelsStatistic();
|
||
sprintf(tmp, "barrels=%2d time=%d max_time=%d", barrels_count, barrels_time, max_time);
|
||
image_insert_sprite(0, 30, tmp);
|
||
|
||
sprintf(tmp, "MODE: night=%d pause=%d", hla_night_mode, auto_mode_pause);
|
||
image_insert_sprite(0, 70, tmp);
|
||
|
||
// рисование бочек
|
||
for (int i = 0; i < BARRELS_COUNT; i++) {
|
||
const auto& b = barrels[i];
|
||
if (b.flags.is_exist) {
|
||
char flag_r = ' ';
|
||
if (b.flags.is_night) {
|
||
flag_r = 'n';
|
||
}
|
||
if (b.flags.is_empty) {
|
||
flag_r = 'e';
|
||
}
|
||
|
||
char flag_l = ' ';
|
||
if (b.flags.robot) {
|
||
flag_l = '*';
|
||
}
|
||
|
||
if (b.flags.is_up) {
|
||
sprintf(tmp, "%cB%d%c", flag_l, i, flag_r);
|
||
image_insert_sprite(4, (b.zone * 5) + 1, tmp);
|
||
} else {
|
||
sprintf(tmp, "%cB%d%c\n%04d", flag_l, i, flag_r, b.software_timer);
|
||
image_insert_sprite(5, (b.zone * 5) + 1, tmp);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
// рисуем роботов
|
||
if (hla_robot1_en) {
|
||
sprintf(tmp, "R1");
|
||
image_insert_sprite(2 + (robot1.mz.is_up ? 0 : 2) - (robot1.mx.correct_sensor ? 1 : 0),
|
||
(robot1.dx.current_zone * 5) + 2 + (robot1_offset_pos * 2) + (robot1.mx.correct_sensor ? 1 : 0),
|
||
tmp);
|
||
}
|
||
|
||
if (hla_robot2_en) {
|
||
sprintf(tmp, "R2");
|
||
image_insert_sprite(2 + (robot2.mz.is_up ? 0 : 2),
|
||
(robot2.dx.current_zone * 5) + 2 + (robot2_offset_pos * 2) - (robot2.mx.correct_sensor ? 1 : 0),
|
||
tmp);
|
||
}
|
||
|
||
for (const auto & r : buffer) {
|
||
write(sock_fd, r, COLS);
|
||
send_str("\n");
|
||
}
|
||
}
|
||
|
||
static void open_socket() {
|
||
sockaddr_in serv_addr{};
|
||
|
||
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||
if (sock_fd < 0) {
|
||
printf("Socket creation error\n");
|
||
exit(-1);
|
||
}
|
||
|
||
// setting socket options
|
||
int flag = 1;
|
||
|
||
if(setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) == -1){
|
||
printf("setsockopt TCP_NODELAY failed for server socket on address 127.0.0.1\n");
|
||
}
|
||
|
||
serv_addr.sin_family = AF_INET;
|
||
serv_addr.sin_port = htons(40000);
|
||
|
||
// Convert IPv4 and IPv6 addresses from text to binary form
|
||
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
|
||
printf("Invalid address/ Address not supported\n");
|
||
exit(-1);
|
||
}
|
||
|
||
if (connect(sock_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
|
||
printf("Connection Failed\n");
|
||
exit(-1);
|
||
}
|
||
}
|
||
|
||
int main() {
|
||
#ifdef DEBUG_CORRECTION
|
||
robot1.mx.correct_sensor = false;
|
||
robot1.dx.current_zone = 5;
|
||
robot2.mx.correct_sensor = false;
|
||
robot2.dx.current_zone = 3;
|
||
hla_correct_command = 1;
|
||
#else
|
||
robot1.mx.correct_sensor = true;
|
||
robot2.mx.correct_sensor = true;
|
||
#endif
|
||
|
||
open_socket();
|
||
|
||
current_tic = 0;
|
||
const char* message = nullptr;
|
||
while (true) {
|
||
_scheduler_software_timer = 1;
|
||
|
||
// подсчитаем статистику
|
||
collectBarrelsStatistic();
|
||
|
||
// грузим не больше 5 барабанов
|
||
// if (barrels_count < 5) {
|
||
// button_load = 1;
|
||
// }
|
||
|
||
// ======= БЛОК КОДА bittons_logic =======
|
||
|
||
// авто сброс кнопок на выгрузке, если там нет барабана
|
||
if (!zone_is_busy(ZONE_UNLOAD)) {
|
||
button_unload = 0;
|
||
button_unload_remove = 0;
|
||
}
|
||
|
||
// кнопка загрузки барабана
|
||
if (button_load) {
|
||
if (!hla_night_mode) {
|
||
if (!zone_is_busy(1)) {
|
||
for (int i = 0; i < BARRELS_COUNT; i++) {
|
||
if (!barrels[i].flags.is_exist) {
|
||
barrels[i].flags.raw_word = 1; // только is_exist
|
||
barrels[i].zone = 1;
|
||
barrels[i].software_timer = -1;
|
||
barrels[i].time_degreasing = hla_time_degreasing;
|
||
barrels[i].time_washing_1a = hla_time_washing_1a;
|
||
barrels[i].time_washing_1b = hla_time_washing_1b;
|
||
barrels[i].time_etching = hla_time_etching;
|
||
barrels[i].time_washing_2a = hla_time_washing_2a;
|
||
barrels[i].time_washing_2b = hla_time_washing_2b;
|
||
barrels[i].time_galvanizing = hla_time_galvanizing;
|
||
barrels[i].time_washing_3a = hla_time_washing_3a;
|
||
barrels[i].time_washing_3b = hla_time_washing_3b;
|
||
barrels[i].time_passivation = hla_time_passivation;
|
||
barrels[i].time_washing_4a = hla_time_washing_4a;
|
||
barrels[i].time_washing_4b = hla_time_washing_4b;
|
||
button_load = 0;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
button_load = 0;
|
||
}
|
||
}
|
||
|
||
// кнопка выгрузки
|
||
if (button_unload_end) {
|
||
button_unload_end = 0;
|
||
remove_barrel_from_zone(0);
|
||
}
|
||
|
||
// кнопка удаления барабана из 22 зоны
|
||
if (button_unload_remove) {
|
||
button_unload_remove = 0;
|
||
remove_barrel_from_zone(22);
|
||
}
|
||
|
||
// ================ КОНЕЦ ================
|
||
|
||
robot_main();
|
||
scheduler_main();
|
||
// increment_zone(ROBOT_ZONE_GAL);
|
||
// increment_zone(ROBOT_ZONE_ETCH);
|
||
send_str("\033c");
|
||
showAll();
|
||
|
||
if (message) {
|
||
std::cout << message << std::endl;
|
||
send_str(message);
|
||
send_str("\n");
|
||
}
|
||
|
||
if (!one_robot_mode) {
|
||
if (!robot2.mx.correct_sensor) {
|
||
if (robot2.dx.current_zone + 1 >= robot1.dx.current_zone) {
|
||
printf("ASSERTION FAILED: FOUND ROBOTS CORRUPTION\n");
|
||
if (robot1_code.PC >= 0)
|
||
debug_print_robot_code(&robot1_code, 1, 0);
|
||
if (robot2_code.PC >= 0)
|
||
debug_print_robot_code(&robot2_code, 2, 0);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (robot1_code.PC >= 0)
|
||
debug_print_robot_code(&robot1_code, 1, sock_fd);
|
||
if (robot2_code.PC >= 0)
|
||
debug_print_robot_code(&robot2_code, 2, sock_fd);
|
||
|
||
#ifdef DEBUG_CORRECTION
|
||
|
||
#endif
|
||
|
||
send_str("cmd >> ");
|
||
std::string in;
|
||
while (true) {
|
||
char tmp[2] = {0, 0};
|
||
ssize_t res = read(sock_fd, tmp, 1);
|
||
if (res < 0) {
|
||
exit(-1);
|
||
}
|
||
if (res == 1) {
|
||
if (tmp[0] == '\n') {
|
||
break;
|
||
}
|
||
in.append(tmp);
|
||
}
|
||
}
|
||
|
||
if (in == "q") {
|
||
break;
|
||
}
|
||
|
||
if (in.empty()) {
|
||
// просто продолжаем циклы
|
||
message = "Continue...";
|
||
} else {
|
||
if (in == "u") {
|
||
button_unload = 1;
|
||
message = "Нажата кнопка выгрузки";
|
||
} else if (in == "1") {
|
||
button_unload_end = 1;
|
||
message = "Нажата кнопка загрузки 1";
|
||
} else if (in == "2") {
|
||
button_load = 1;
|
||
message = "Нажата кнопка загрузки 2";
|
||
} else if (in == "n") {
|
||
hla_night_mode = !hla_night_mode;
|
||
message = "Переключен ночной режим";
|
||
} else if (in == "p") {
|
||
auto_mode_pause = !auto_mode_pause;
|
||
message = "Переключен режим паузы";
|
||
} else {
|
||
message = "Неизвестная команда. q - выход, u - выгрузка, 1 - загрузка 1, 2 - загрузка 2";
|
||
}
|
||
}
|
||
current_tic++;
|
||
}
|
||
|
||
fsync(sock_fd);
|
||
close(sock_fd);
|
||
return 0;
|
||
} |