diff --git a/dc11.cpp b/dc11.cpp index a2a5c03..29a8627 100644 --- a/dc11.cpp +++ b/dc11.cpp @@ -1,6 +1,7 @@ // (C) 2024 by Folkert van Heusden // Released under MIT license +#include "gen.h" #if defined(ESP32) #include #endif @@ -17,6 +18,11 @@ #include #include #endif +#if IS_POSIX +#include +#include +#include +#endif #include #include @@ -40,7 +46,7 @@ bool setup_telnet_session(const int fd) uint8_t will_echo[] = { 0xff, 0xfb, 0x01 }; uint8_t dont_echo[] = { 0xff, 0xfe, 0x01 }; uint8_t noecho[] = { 0xff, 0xfd, 0x2d }; - uint8_t charset[] = { 0xff, 0xfb, 0x01 }; + // uint8_t charset[] = { 0xff, 0xfb, 0x01 }; if (write(fd, dont_auth, sizeof dont_auth) != sizeof dont_auth) return false; @@ -93,6 +99,13 @@ dc11::~dc11() #if defined(ESP32) // won't work due to freertos thread +#elif IS_POSIX + close(serial_fd); + + if (serial_th) { + serial_th->join(); + delete serial_th; + } #endif } @@ -285,10 +298,59 @@ void dc11::set_serial(const int bitrate, const int rx, const int tx) xTaskCreate(&dc11_thread_wrapper_serial_handler, "dc11_tty", 3072, this, 1, nullptr); } +#elif IS_POSIX +void dc11::set_serial(const int bitrate, const std::string & device) +{ + serial_fd = open(device.c_str(), O_RDWR); + if (serial_fd == -1) + return; // TODO error handling + + // from https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c + termios tty { }; + if (tcgetattr(serial_fd, &tty) == -1) { + close(serial_fd); + return; + } + + cfsetospeed(&tty, bitrate); + cfsetispeed(&tty, bitrate); + + tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars + // disable IGNBRK for mismatched speed tests; otherwise receive break + // as \000 chars + tty.c_iflag &= ~IGNBRK; // disable break processing + tty.c_lflag = 0; // no signaling chars, no echo, + // no canonical processing + tty.c_oflag = 0; // no remapping, no delays + tty.c_cc[VMIN] = 0; // read doesn't block + tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout + + tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl + + tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls, + // enable reading + tty.c_cflag &= ~(PARENB | PARODD); // shut off parity + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CRTSCTS; + + if (tcsetattr(serial_fd, TCSANOW, &tty) == -1) { + close(serial_fd); + return; + } + + serial_th = new std::thread(&dc11::serial_handler, this); +} +#endif void dc11::serial_handler() { +#if IS_POSIX + pollfd fds[] { { serial_fd, POLLIN, 0 } }; +#endif + while(!stop_flag) { + char c = 0; +#if defined(ESP32) yield(); size_t n_available = 0; @@ -298,9 +360,19 @@ void dc11::serial_handler() continue; } - char c = 0; if (uart_read_bytes(ESP32_UART, &c, 1, 100) == 0) continue; +#elif IS_POSIX + int rc_poll = poll(fds, 1, 100); + if (rc_poll == -1) + break; + if (rc_poll == 0) + continue; + + int rc_read = read(serial_fd, &c, 1); + if (rc_read <= 0) + break; +#endif // 3 is reserved for a serial port constexpr const int serial_line = 3; @@ -322,7 +394,6 @@ void dc11::serial_handler() trigger_interrupt(serial_line, false); } } -#endif void dc11::reset() { @@ -446,16 +517,21 @@ void dc11::write_word(const uint16_t addr, const uint16_t v) else TRACE("DC11: transmit %c on line %d", c, line_nr); -#if defined(ESP32) if (line_nr == 3) { - if (serial_thread_running) + if (serial_thread_running) { +#if defined(ESP32) uart_write_bytes(ESP32_UART, &c, 1); +#elif IS_POSIX + if (write(serial_fd, &c, 1) != 1) { + // TODO error handling + } +#endif + } if (is_tx_interrupt_enabled(line_nr)) trigger_interrupt(line_nr, true); return; } -#endif SOCKET fd = pfds[dc11_n_lines + line_nr].fd; if (fd != INVALID_SOCKET && write(fd, &c, 1) != 1) { diff --git a/dc11.h b/dc11.h index c9cc3be..1c4dc9d 100644 --- a/dc11.h +++ b/dc11.h @@ -48,9 +48,11 @@ private: #endif std::vector recv_buffers[dc11_n_lines]; std::mutex input_lock[dc11_n_lines]; -#if defined(ESP32) std::atomic_bool serial_thread_running { false }; bool serial_enabled { false }; +#if IS_POSIX + std::thread *serial_th { nullptr }; + int serial_fd { -1 }; #endif void trigger_interrupt(const int line_nr, const bool is_tx); @@ -70,6 +72,9 @@ public: #if defined(ESP32) void set_serial(const int bitrate, const int rx, const int tx); void serial_handler(); +#elif IS_POSIX + void set_serial(const int bitrate, const std::string & device_name); + void serial_handler(); #endif uint8_t read_byte(const uint16_t addr); diff --git a/main.cpp b/main.cpp index 2e79be2..f962147 100644 --- a/main.cpp +++ b/main.cpp @@ -329,6 +329,7 @@ void help() printf("-X do not include timestamp in logging\n"); printf("-J x run validation suite x against the CPU emulation\n"); printf("-M log metrics\n"); + printf("-1 x use x as device for DC-11\n"); } int main(int argc, char *argv[]) @@ -368,14 +369,20 @@ int main(int argc, char *argv[]) std::string deserialize; + std::optional dc11_device; + int opt = -1; - while((opt = getopt(argc, argv, "hD:MT:Br:R:p:ndtL:bl:s:Q:N:J:XS:P")) != -1) + while((opt = getopt(argc, argv, "hD:MT:Br:R:p:ndtL:bl:s:Q:N:J:XS:P1:")) != -1) { switch(opt) { case 'h': help(); return 1; + case '1': + dc11_device = optarg; + break; + case 'D': deserialize = optarg; break; @@ -593,6 +600,8 @@ int main(int argc, char *argv[]) // TODO dc11 *dc11_ = new dc11(1100, b); + if (dc11_device.has_value()) + dc11_->set_serial(115200, dc11_device.value()); b->add_DC11(dc11_); tm_11 *tm_11_ = new tm_11(b);