This repository has been archived on 2024-09-18. You can view files and clone it, but cannot push or open issues or pull requests.
sdp-scheduler/emulator.cpp

432 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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;
}
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;
}