From 4b7e0fe11c1ddb739ae6c1d0eb4eb2d63b573f74 Mon Sep 17 00:00:00 2001 From: Chris Osborn Date: Mon, 20 Oct 2025 08:46:03 -0700 Subject: [PATCH] Replace fnUART* classes and switch to IOChannel abstraction New abstraction supports any streaming I/O type (serial, network, USB) with a single consistent API. --- fujinet_pc.cmake | 19 +- include/debug.h | 4 +- lib/bus/adamnet/adamnet.cpp | 4 +- lib/bus/adamnet/adamnet.h | 8 +- lib/bus/bus.h | 1 - lib/bus/drivewire/BeckerSocket.cpp | 678 ++++++++++++++ lib/bus/drivewire/BeckerSocket.h | 80 ++ lib/bus/drivewire/drivewire.cpp | 282 +++--- lib/bus/drivewire/drivewire.h | 116 ++- lib/bus/drivewire/dwcom/dwbecker.cpp | 866 ------------------ lib/bus/drivewire/dwcom/dwbecker.h | 173 ---- lib/bus/drivewire/dwcom/dwport.cpp | 5 - lib/bus/drivewire/dwcom/dwport.h | 30 - lib/bus/drivewire/dwcom/dwserial.cpp | 40 - lib/bus/drivewire/dwcom/dwserial.h | 53 -- lib/bus/drivewire/dwcom/fnDwCom.cpp | 128 --- lib/bus/drivewire/dwcom/fnDwCom.h | 112 --- lib/bus/drivewire/dwprotocol.c | 743 --------------- lib/bus/drivewire/dwwin.c | 285 ------ lib/bus/rs232/rs232.cpp | 71 +- lib/bus/rs232/rs232.h | 16 +- lib/bus/sio/{siocom/netsio.cpp => NetSIO.cpp} | 441 +++------ lib/bus/sio/NetSIO.h | 118 +++ lib/bus/sio/sio.cpp | 206 +++-- lib/bus/sio/sio.h | 98 +- lib/bus/sio/siocom/fnSioCom.cpp | 258 ------ lib/bus/sio/siocom/fnSioCom.h | 96 -- lib/bus/sio/siocom/netsio.h | 102 --- lib/bus/sio/siocom/netsio_proto.h | 44 - lib/bus/sio/siocom/serialsio.cpp | 15 - lib/bus/sio/siocom/serialsio.h | 61 -- lib/bus/sio/siocom/sioport.cpp | 9 - lib/bus/sio/siocom/sioport.h | 42 - lib/config/fnConfig.h | 13 +- lib/config/fnc_serial.cpp | 19 +- lib/device/adamnet/fuji.cpp | 6 +- lib/device/adamnet/modem.cpp | 1 - lib/device/drivewire/cassette.cpp | 3 +- lib/device/drivewire/cpm.cpp | 19 +- lib/device/drivewire/dload.cpp | 51 +- lib/device/drivewire/fuji.cpp | 96 +- lib/device/drivewire/modem.cpp | 249 +---- lib/device/drivewire/modem.h | 6 - lib/device/drivewire/network.cpp | 38 +- lib/device/iwm/cpm.cpp | 1 - lib/device/iwm/modem.cpp | 1 - lib/device/rs232/fuji.cpp | 3 +- lib/device/rs232/modem.cpp | 16 +- lib/device/rs232/rs232cpm.cpp | 2 +- lib/device/sio/cassette.cpp | 9 +- lib/device/sio/fuji.cpp | 13 +- lib/device/sio/modem.cpp | 12 +- lib/device/sio/pclink.cpp | 6 +- lib/device/sio/udpstream.cpp | 2 +- lib/device/sio/udpstream.h | 2 +- lib/hardware/ACMChannel.cpp | 234 +++++ lib/hardware/ACMChannel.h | 39 + lib/hardware/COMChannel.cpp | 285 ++++++ lib/hardware/COMChannel.h | 70 ++ lib/hardware/ESP32UARTChannel.cpp | 152 +++ lib/hardware/ESP32UARTChannel.h | 100 ++ lib/hardware/IOChannel.cpp | 235 +++++ lib/hardware/IOChannel.h | 97 ++ lib/hardware/RS232ChannelProtocol.h | 17 + lib/hardware/TTYChannel.cpp | 403 ++++++++ lib/hardware/TTYChannel.h | 67 ++ lib/hardware/UARTChannel.h | 18 + lib/hardware/fnUART.cpp | 558 ----------- lib/hardware/fnUART.h | 164 ---- lib/hardware/fnUARTUnix.cpp | 597 ------------ lib/hardware/fnUARTWindows.cpp | 445 --------- lib/http/httpServiceConfigurator.cpp | 12 +- lib/http/httpServiceParser.cpp | 3 +- lib/runcpm/abstraction_fujinet.h | 2 +- lib/runcpm/abstraction_fujinet_apple2.h | 1 - src/main.cpp | 2 +- 76 files changed, 3318 insertions(+), 5955 deletions(-) create mode 100644 lib/bus/drivewire/BeckerSocket.cpp create mode 100644 lib/bus/drivewire/BeckerSocket.h delete mode 100644 lib/bus/drivewire/dwcom/dwbecker.cpp delete mode 100644 lib/bus/drivewire/dwcom/dwbecker.h delete mode 100644 lib/bus/drivewire/dwcom/dwport.cpp delete mode 100644 lib/bus/drivewire/dwcom/dwport.h delete mode 100644 lib/bus/drivewire/dwcom/dwserial.cpp delete mode 100644 lib/bus/drivewire/dwcom/dwserial.h delete mode 100644 lib/bus/drivewire/dwcom/fnDwCom.cpp delete mode 100644 lib/bus/drivewire/dwcom/fnDwCom.h delete mode 100644 lib/bus/drivewire/dwprotocol.c delete mode 100644 lib/bus/drivewire/dwwin.c rename lib/bus/sio/{siocom/netsio.cpp => NetSIO.cpp} (66%) create mode 100644 lib/bus/sio/NetSIO.h delete mode 100644 lib/bus/sio/siocom/fnSioCom.cpp delete mode 100644 lib/bus/sio/siocom/fnSioCom.h delete mode 100644 lib/bus/sio/siocom/netsio.h delete mode 100644 lib/bus/sio/siocom/netsio_proto.h delete mode 100644 lib/bus/sio/siocom/serialsio.cpp delete mode 100644 lib/bus/sio/siocom/serialsio.h delete mode 100644 lib/bus/sio/siocom/sioport.cpp delete mode 100644 lib/bus/sio/siocom/sioport.h create mode 100644 lib/hardware/ACMChannel.cpp create mode 100644 lib/hardware/ACMChannel.h create mode 100644 lib/hardware/COMChannel.cpp create mode 100644 lib/hardware/COMChannel.h create mode 100644 lib/hardware/ESP32UARTChannel.cpp create mode 100644 lib/hardware/ESP32UARTChannel.h create mode 100644 lib/hardware/IOChannel.cpp create mode 100644 lib/hardware/IOChannel.h create mode 100644 lib/hardware/RS232ChannelProtocol.h create mode 100644 lib/hardware/TTYChannel.cpp create mode 100644 lib/hardware/TTYChannel.h create mode 100644 lib/hardware/UARTChannel.h delete mode 100644 lib/hardware/fnUART.cpp delete mode 100644 lib/hardware/fnUART.h delete mode 100644 lib/hardware/fnUARTUnix.cpp delete mode 100644 lib/hardware/fnUARTWindows.cpp diff --git a/fujinet_pc.cmake b/fujinet_pc.cmake index 7a82bb968..04e96d180 100644 --- a/fujinet_pc.cmake +++ b/fujinet_pc.cmake @@ -163,8 +163,11 @@ set(SOURCES src/main.cpp lib/utils/U8Char.h lib/utils/U8Char.cpp lib/hardware/fnWiFi.h lib/hardware/fnDummyWiFi.h lib/hardware/fnDummyWiFi.cpp lib/hardware/led.h lib/hardware/led.cpp - lib/hardware/fnUART.h lib/hardware/fnUART.cpp - lib/hardware/fnUARTUnix.cpp lib/hardware/fnUARTWindows.cpp + lib/hardware/ACMChannel.cpp lib/hardware/ACMChannel.h + lib/hardware/COMChannel.h lib/hardware/COMChannel.cpp + lib/hardware/IOChannel.cpp lib/hardware/IOChannel.h + lib/hardware/TTYChannel.cpp lib/hardware/TTYChannel.h + lib/hardware/UARTChannel.h lib/hardware/fnSystem.h lib/hardware/fnSystem.cpp lib/hardware/fnSystemNet.cpp lib/FileSystem/fnDirCache.h lib/FileSystem/fnDirCache.cpp lib/FileSystem/fnFileCache.h lib/FileSystem/fnFileCache.cpp @@ -263,10 +266,7 @@ if(FUJINET_TARGET STREQUAL "ATARI") list(APPEND SOURCES lib/bus/sio/sio.h lib/bus/sio/sio.cpp - lib/bus/sio/siocom/sioport.h lib/bus/sio/siocom/sioport.cpp - lib/bus/sio/siocom/serialsio.h lib/bus/sio/siocom/serialsio.cpp - lib/bus/sio/siocom/netsio.h lib/bus/sio/siocom/netsio.cpp - lib/bus/sio/siocom/fnSioCom.h lib/bus/sio/siocom/fnSioCom.cpp + lib/bus/sio/NetSIO.h lib/bus/sio/NetSIO.cpp lib/media/atari/diskType.h lib/media/atari/diskType.cpp lib/media/atari/diskTypeAtr.h lib/media/atari/diskTypeAtr.cpp lib/media/atari/diskTypeAtx.h lib/media/atari/diskTypeAtx.cpp @@ -361,16 +361,13 @@ if(FUJINET_TARGET STREQUAL "COCO") list(APPEND SOURCES lib/bus/drivewire/drivewire.h lib/bus/drivewire/drivewire.cpp - lib/bus/drivewire/dwcom/fnDwCom.h lib/bus/drivewire/dwcom/fnDwCom.cpp - lib/bus/drivewire/dwcom/dwport.h lib/bus/drivewire/dwcom/dwport.cpp - lib/bus/drivewire/dwcom/dwserial.h lib/bus/drivewire/dwcom/dwserial.cpp - lib/bus/drivewire/dwcom/dwbecker.h lib/bus/drivewire/dwcom/dwbecker.cpp + lib/bus/drivewire/BeckerSocket.h lib/bus/drivewire/BeckerSocket.cpp lib/media/drivewire/mediaType.h lib/media/drivewire/mediaType.cpp lib/media/drivewire/mediaTypeDSK.h lib/media/drivewire/mediaTypeDSK.cpp lib/media/drivewire/mediaTypeMRM.h lib/media/drivewire/mediaTypeMRM.cpp lib/media/drivewire/mediaTypeVDK.h lib/media/drivewire/mediaTypeVDK.cpp - + lib/device/drivewire/fuji.h lib/device/drivewire/fuji.cpp lib/device/drivewire/network.h lib/device/drivewire/network.cpp lib/device/drivewire/dload.h lib/device/drivewire/dload.cpp diff --git a/include/debug.h b/include/debug.h index ad8963798..abdd75295 100644 --- a/include/debug.h +++ b/include/debug.h @@ -23,9 +23,9 @@ #ifdef DEBUG #ifdef ESP_PLATFORM // Use FujiNet debug serial output - #include "../lib/hardware/fnUART.h" + #include "../lib/hardware/ESP32UARTChannel.h" #define Serial fnDebugConsole -#if defined(PINMAP_RS232_S3) /*|| defined(PINMAP_ESP32S3_XDRIVE)*/ +#ifdef PINMAP_RS232_S3 #define Debug_print(...) printf( __VA_ARGS__ ) #define Debug_printf(...) printf( __VA_ARGS__ ) #define Debug_println(...) do { printf(__VA_ARGS__); printf("\n"); } while (0) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index 9eac6280e..6373b2017 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -332,7 +332,9 @@ void systemBus::setup() gpio_isr_handler_add((gpio_num_t)PIN_ADAMNET_RESET, adamnet_reset_isr_handler, (void *)PIN_CARD_DETECT_FIX); // Set up UART - _port.begin(ADAMNET_BAUDRATE); + _port.begin(ChannelConfig() + .baud(ADAMNET_BAUDRATE) + ); } void systemBus::shutdown() diff --git a/lib/bus/adamnet/adamnet.h b/lib/bus/adamnet/adamnet.h index 3276da431..e287bdf81 100755 --- a/lib/bus/adamnet/adamnet.h +++ b/lib/bus/adamnet/adamnet.h @@ -5,7 +5,7 @@ * AdamNet Routines */ -#include "fnUART.h" +#include "UARTChannel.h" #include #include @@ -247,7 +247,7 @@ class systemBus adamFuji *_fujiDev = nullptr; adamPrinter *_printerDev = nullptr; - UARTManager _port = UARTManager(FN_UART_BUS); + UARTChannel _port; void _adamnet_process_cmd(); void _adamnet_process_queue(); @@ -285,12 +285,12 @@ class systemBus // Everybody thinks "oh I know how a serial port works, I'll just // access it directly and bypass the bus!" ಠ_ಠ - size_t read(void *buffer, size_t length) { return _port.readBytes(buffer, length); } + size_t read(void *buffer, size_t length) { return _port.read(buffer, length); } size_t read() { return _port.read(); } size_t write(const void *buffer, size_t length) { return _port.write(buffer, length); } size_t write(int n) { return _port.write(n); } size_t available() { return _port.available(); } - void flush() { _port.flush(); } + void flush() { _port.flushOutput(); } size_t print(int n, int base = 10) { return _port.print(n, base); } size_t print(const char *str) { return _port.print(str); } size_t print(const std::string &str) { return _port.print(str); } diff --git a/lib/bus/bus.h b/lib/bus/bus.h index 21aa136a5..99d792ab4 100644 --- a/lib/bus/bus.h +++ b/lib/bus/bus.h @@ -47,7 +47,6 @@ #ifdef BUILD_RS232 #include "rs232/rs232.h" -#define FN_BUS_PORT fnUartBUS #endif #ifdef BUILD_CX16 diff --git a/lib/bus/drivewire/BeckerSocket.cpp b/lib/bus/drivewire/BeckerSocket.cpp new file mode 100644 index 000000000..442b521fc --- /dev/null +++ b/lib/bus/drivewire/BeckerSocket.cpp @@ -0,0 +1,678 @@ +#ifdef BUILD_COCO + +#include "BeckerSocket.h" +#include "fnSystem.h" +#include "fnWiFi.h" +#include "compat_string.h" + +#include "../../include/debug.h" + +#ifndef ESP_PLATFORM + +#if !defined(_WIN32) +# include +# include +#endif + +#ifndef MSG_NOSIGNAL +# define MSG_NOSIGNAL 0 +# if defined(__APPLE__) || defined(__MACH__) +// MSG_NOSIGNAL does not exists on older macOS, use SO_NOSIGPIPE +# define USE_SO_NOSIGPIPE +# endif +#endif + +#endif // !ESP_PLATFORM + +#define DW_DEFAULT_BAUD 57600 + +#if defined(_WIN32) +#define DW_CONNECT_ERR WSAEWOULDBLOCK +#define DW_EINTR WSAEINTR +#define DW_ETIMEDOUT WSAETIMEDOUT +#define DW_REUSEADDR SO_EXCLUSIVEADDRUSE +#else +#define DW_CONNECT_ERR EINPROGRESS +#define DW_EINTR EINTR +#define DW_ETIMEDOUT ETIMEDOUT +#define DW_REUSEADDR SO_REUSEADDR +#endif + +// Constructor +BeckerSocket::BeckerSocket() : + _host(""), + _ip(IPADDR_NONE), + _port(BECKER_DEFAULT_PORT), + _listening(true), + _fd(-1), + _listen_fd(-1), + _state(BeckerStopped), + _errcount(0) +{} + +BeckerSocket::~BeckerSocket() +{ + end(); +} + +void BeckerSocket::begin(std::string host, int baud) +{ + if (_state != BeckerStopped) + end(); + + _host = host; + read_timeout_ms = 500; + + // listen or connect + start_connection(); +} + +void BeckerSocket::end() +{ + // close sockets + if (_fd >= 0) + { + shutdown(_fd, 0); + closesocket(_fd); + _fd = -1; + } + if (_listen_fd >= 0) + { + closesocket(_listen_fd); + _listen_fd = -1; + Debug_printf("### BeckerSocket stopped ###\n"); + } + + // wait a while, otherwise wifi may turn off too quickly (during shutdown) + fnSystem.delay(50); + + _state = BeckerStopped; +} + +/* Clears input buffer and flushes out transmit buffer waiting at most + waiting MAX_FLUSH_WAIT_TICKS until all sends are completed +*/ +void BeckerSocket::flushOutput() +{ + // only in connected state + if (_state != BeckerConnected) + return; + + wait_sock_writable(250); +} + +void BeckerSocket::start_connection() +{ + if (_listening) + listen_for_connection(); + else + make_connection(); +} + +void BeckerSocket::listen_for_connection() +{ + // Wait for WiFi + if (!fnWiFi.connected()) + { + Debug_println("BeckerSocket: No WiFi!"); + // suspend for 0.5 or 2 sec, depending on _errcount + suspend(1000, 5000, 5); + return; + } + + Debug_printf("Setting up BeckerSocket: listening on %s:%d\n", _host.c_str(), _port); + + // Create listening socket + _listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (_listen_fd < 0) + { + Debug_printf("BeckerSocket: failed to create socket: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + suspend(BECKER_SUSPEND_MS); + return; + } + + // Set socket option + int enable = 1; + if (setsockopt(_listen_fd, SOL_SOCKET, DW_REUSEADDR, (char *) &enable, + sizeof(enable)) != 0) + { + Debug_printf("BeckerSocket: setsockopt failed: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + closesocket(_listen_fd); + _listen_fd = -1; + suspend(BECKER_SUSPEND_MS); + return; + } + + // Local address to listen on + if (_host.empty() || _host == "*") + { + _ip = IPADDR_ANY; + } + else + { + _ip = get_ip4_addr_by_name(_host.c_str()); + if (_ip == IPADDR_NONE) + { + Debug_println("BeckerSocket: failed to resolve host name"); + closesocket(_listen_fd); + _listen_fd = -1; + suspend(BECKER_SUSPEND_MS); + return; + } + } + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = _ip; + addr.sin_port = htons(_port); + + // Bind to listening address + if (bind(_listen_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) + { + Debug_printf("BeckerSocket: bind failed: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + closesocket(_listen_fd); + _listen_fd = -1; + suspend(BECKER_SUSPEND_MS); + return; + } + + // Listen for incoming connection + if (listen(_listen_fd, 1) != 0) + { + Debug_printf("BeckerSocket: listen failed: %d %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + closesocket(_listen_fd); + _listen_fd = -1; + suspend(BECKER_SUSPEND_MS); + return; + } + + // Set socket non-blocking + if (!compat_socket_set_nonblocking(_listen_fd)) + { + Debug_printf("BeckerSocket: failed to set non-blocking mode: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + closesocket(_listen_fd); + _listen_fd = -1; + suspend(BECKER_SUSPEND_MS); + return; + } + + // Finally setup + _errcount = 0; // used by suspend() + _state = BeckerWaitConn; + Debug_printf("### BeckerSocket accepting connections ###\n"); +} + +void BeckerSocket::make_connection() +{ + // Wait for WiFi + if (!fnWiFi.connected()) + { + Debug_println("BeckerSocket: No WiFi!"); + // suspend for 0.5 or 2 sec, depending on _errcount + suspend(1000, 5000, 5); + return; + } + + Debug_printf("Setting up BeckerSocket: connecting to %s:%d\n", _host.c_str(), _port); + + // Create connection socket + _fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (_fd < 0) + { + Debug_printf("BeckerSocket: failed to create socket: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + suspend(BECKER_SUSPEND_MS); + return; + } + +#ifdef USE_SO_NOSIGPIPE + // Set NOSIGPIPE socket option (old macOS) + int enable = 1; + if (setsockopt(_fd, SOL_SOCKET, SO_NOSIGPIPE, (char *)&enable, sizeof(enable)) < 0) + { + Debug_printf("BeckerSocket: setsockopt failed: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + suspend(BECKER_SUSPEND_MS); + return; + } +#endif + + // Set socket non-blocking + if (!compat_socket_set_nonblocking(_fd)) + { + Debug_printf("BeckerSocket: failed to set non-blocking mode: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + suspend(BECKER_SUSPEND_MS); + return; + } + + // Remote address + if (_host.empty()) + { + _ip = IPADDR_LOOPBACK; + } + else + { + _ip = get_ip4_addr_by_name(_host.c_str()); + if (_ip == IPADDR_NONE) + { + Debug_println("BeckerSocket: failed to resolve host name"); + suspend(BECKER_SUSPEND_MS); + return; + } + } + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = _ip; + addr.sin_port = htons(_port); + + // Connect to remote address + int res = connect(_fd, (struct sockaddr *)&addr, sizeof(addr)); + int err = compat_getsockerr(); + + if (res < 0 && err != DW_CONNECT_ERR) + { + Debug_printf("BeckerSocket: connect failed: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + suspend(BECKER_SUSPEND_MS); + return; + } + + if (!wait_sock_writable(BECKER_CONNECT_TMOUT)) + { + Debug_printf("BeckerSocket: socket not ready\n"); + suspend(BECKER_SUSPEND_MS); + return; + } + + // Finally setup + _errcount = 0; + _state = BeckerConnected; + Debug_print("### BeckerSocket connected ###\n"); +} + +bool BeckerSocket::accept_pending_connection(int ms) +{ + // if listening socket has new connection accept it + return(wait_sock_readable(ms, true) && accept_connection()); +} + +bool BeckerSocket::accept_connection() +{ + struct sockaddr_in addr; + int as = sizeof(struct sockaddr_in); + + // Accept connection + _fd = accept(_listen_fd, (struct sockaddr *)&addr, (socklen_t *)&as); + if (_fd < 0) + { + Debug_printf("BeckerSocket: accept failed: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + return false; + } + Debug_printf("BeckerSocket: connection from: %s\r\n", inet_ntoa(addr.sin_addr)); + + // Set socket options + int val = 1; + if (setsockopt(_fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&val, sizeof(val)) < 0) + { + Debug_printf("BeckerSocket warning: failed to set KEEPALIVE on socket\n"); + } + if (setsockopt(_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)) < 0) + { + Debug_printf("BeckerSocket warning: failed to set NODELAY on socket\n"); + } + + // Set socket non-blocking + if (!compat_socket_set_nonblocking(_fd)) + { + Debug_printf("BeckerSocket: failed to set non-blocking connection: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + shutdown(_fd, 0); + closesocket(_fd); + _fd = -1; + return false; + } + + // We are connected ! + Debug_print("### BeckerSocket connected ###\n"); + _state = BeckerConnected; + return true; +} + +void BeckerSocket::suspend(int short_ms, int long_ms, int threshold) +{ + if (_fd >= 0) + { + closesocket(_fd); + _fd = -1; + } + _errcount++; + _suspend_time = fnSystem.millis(); + _suspend_period = short_ms; + if (threshold > 0 && _errcount > threshold && long_ms > 0) + _suspend_period = long_ms; + Debug_printf("Suspending BeckerSocket for %d ms\n", _suspend_period); + _state = BeckerSuspended; +} + +void BeckerSocket::suspend_on_disconnect() +{ + if (_listening && _listen_fd >=0) + { + if (_fd >= 0) + { + closesocket(_fd); + _fd = -1; + } + // go directly into waiting for connection state + _state = BeckerWaitConn; + } + else + { + // wait before reconnecting + suspend(BECKER_SUSPEND_MS); + } +} + +bool BeckerSocket::resume() +{ + // Debug_print("Resuming BeckerSocket\n"); + if (_listening) + { + if (_listen_fd >= 0) + { + // go directly into waiting for connection state + _state = BeckerWaitConn; + return true; + } + + } + // listen or connect + start_connection(); + return (_state != BeckerSuspended); +} + +bool BeckerSocket::suspend_period_expired() +{ + return (fnSystem.millis() - _suspend_time > _suspend_period); +} + +bool BeckerSocket::connected() +{ + uint8_t dummy; + bool con = false; + int res = recv(_fd, (char *)&dummy, 1, MSG_PEEK); + if (res > 0) + { + con = true; + } + else if (res == 0) + { + Debug_print("### BeckerSocket disconnected ###\n"); + } + else + { + int err = compat_getsockerr(); + switch (err) + { +#if defined(_WIN32) + case WSAEWOULDBLOCK: +#else + case EWOULDBLOCK: + case ENOENT: // Caused by VFS +#endif + con = true; + break; + default: + Debug_printf("BeckerSocket: connection error: %d - %s\n", + compat_getsockerr(), compat_sockstrerror(err)); + break; + } + } + return con; +} + +bool BeckerSocket::poll_connection(int ms) +{ + switch (_state) + { + case BeckerSuspended: + if (!suspend_period_expired()) + { + // still suspended +#ifndef ESP_PLATFORM + fnSystem.delay(ms); // be nice to CPU +#endif + return false; + } + // resume + return resume(); + + case BeckerWaitConn: + return accept_pending_connection(ms); // true if new connection was accepted + + case BeckerStopped: +#ifndef ESP_PLATFORM + fnSystem.delay(ms); // be nice to CPU +#endif + return false; + + case BeckerConnected: + break; + } + + if (wait_sock_readable(ms) && !connected()) + { + // connection was closed or it has an error + suspend_on_disconnect(); + } + + return false; +} + +timeval BeckerSocket::timeval_from_ms(const uint32_t millis) +{ + timeval tv; + tv.tv_sec = millis / 1000; + tv.tv_usec = (millis - (tv.tv_sec * 1000)) * 1000; + return tv; +} + +bool BeckerSocket::wait_sock_readable(uint32_t timeout_ms, bool listener) +{ + timeval timeout_tv; + fd_set readfds; + int result; + int fd = listener ? _listen_fd : _fd; + + for(;;) + { + // Setup a select call to block for socket data or a timeout + timeout_tv = timeval_from_ms(timeout_ms); + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + result = select(fd + 1, &readfds, nullptr, nullptr, &timeout_tv); + + // select error + if (result < 0) + { + int err = compat_getsockerr(); + if (err == DW_EINTR) + { + // TODO adjust timeout_tv + continue; + } + Debug_printf("BeckerSocket: wait_sock_readable() select error %d: %s\n", err, compat_sockstrerror(err)); + return false; + } + + // select timeout + if (result == 0) + return false; + + // this shouldn't happen, if result > 0 our fd has to be in the list! + if (!FD_ISSET(fd, &readfds)) + { + Debug_println("BeckerSocket: wait_sock_readable() unexpected select result"); + return false; + } + break; + } + return true; +} + +bool BeckerSocket::wait_sock_writable(uint32_t timeout_ms) +{ + timeval timeout_tv; + fd_set writefds; + fd_set errfds; + int result; + + for(;;) + { + timeout_tv = timeval_from_ms(timeout_ms); + // select for write + FD_ZERO(&writefds); + FD_SET(_fd, &writefds); + // select for error too + FD_ZERO(&errfds); + FD_SET(_fd, &errfds); + + result = select(_fd + 1, nullptr, &writefds, &errfds, &timeout_tv); + + // select error + if (result < 0) + { + int err = compat_getsockerr(); + if (err == DW_EINTR) + { + // TODO adjust timeout_tv + continue; + } + Debug_printf("BeckerSocket wait_sock_writable() select error %d: %s\n", err, compat_sockstrerror(err)); + return false; + } + + // select timeout + if (result == 0) + { + int err = DW_ETIMEDOUT; + // set errno + compat_setsockerr(err); + return false; + } + // Check for error on socket + { + int sockerr; + socklen_t len = (socklen_t)sizeof(int); + // Store any socket error value in sockerr + int res = getsockopt(_fd, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &len); + if (res < 0) + { + // Failed to retrieve SO_ERROR + int err = compat_getsockerr(); + Debug_printf("getsockopt on fd %d, errno: %d - %s\n", _fd, err ,compat_sockstrerror(err)); + return false; + } + // Retrieved SO_ERROR and found that we have an error condition + if (sockerr != 0) + { + Debug_printf("socket error on fd %d, errno: %d - %s\n", _fd, sockerr, compat_sockstrerror(sockerr)); + // set errno + compat_setsockerr(sockerr); + return false; + } + } + //Debug_print("socket is ready for write\n"); + break; + } + return true; +} + +void BeckerSocket::updateFIFO() +{ + poll_connection(1); + + // only in connected state + if (_state != BeckerConnected) + return; + + // check if socket is still connected + if (!connected()) + { + // connection was closed or it has an error + suspend_on_disconnect(); + return; + } + +#if defined(_WIN32) + unsigned long count; + int res = ioctlsocket(_fd, FIONREAD, &count); + res = res != 0 ? -1 : count; +#else + int count; + int res = ioctl(_fd, FIONREAD, &count); + res = res < 0 ? -1 : count; +#endif + + if (res > 0) + { + ssize_t result; + + for (count = res; count; count -= result) + { + size_t old_len = _fifo.size(); + _fifo.resize(old_len + count); + result = recv(_fd, &_fifo[old_len], count, 0); + if (result < 0) + result = 0; + _fifo.resize(old_len + result); + } + + } + + return; +} + +size_t BeckerSocket::dataOut(const void *buffer, size_t size) +{ + uint32_t timeout_ms=BECKER_IOWAIT_MS; + + if (!wait_sock_writable(timeout_ms)) + { + int err = compat_getsockerr(); + if (err == DW_ETIMEDOUT) + { + Debug_printf("BeckerSocket: write_sock() TIMEOUT\n"); + } + else + { + suspend_on_disconnect(); + } + return -1; + } + + ssize_t result = send(_fd, (char *)buffer, size, 0); + if (result < 0) + { + Debug_printf("BeckerSocket write_sock() error %d: %s\n", + compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); + suspend_on_disconnect(); + } + return result; +} + +void BeckerSocket::setHost(std::string host, int port) +{ + _host = host; + _port = port; +} + +#endif // BUILD_COCO diff --git a/lib/bus/drivewire/BeckerSocket.h b/lib/bus/drivewire/BeckerSocket.h new file mode 100644 index 000000000..0c4373cac --- /dev/null +++ b/lib/bus/drivewire/BeckerSocket.h @@ -0,0 +1,80 @@ +#ifndef BECKERSOCKET_H +#define BECKERSOCKET_H + +#include "IOChannel.h" +#include "fnDNS.h" + +#define BECKER_DEFAULT_PORT 65504 +#define BECKER_IOWAIT_MS 500 +#define BECKER_CONNECT_TMOUT 2000 +#define BECKER_SUSPEND_MS 5000 + +enum BeckerState { + BeckerStopped, + BeckerWaitConn, + BeckerConnected, + BeckerSuspended, +}; + +class BeckerSocket : public IOChannel +{ +private: + std::string _host; + in_addr_t _ip; + uint16_t _port; + + // is waiting for connection (listening) or connecting to? + bool _listening; + + // file descriptors + int _fd; + int _listen_fd; + + // state machine handlers for poll(), read() and write() + BeckerState _state; + + // error counter + int _errcount; +#ifdef ESP_PLATFORM + unsigned long _suspend_time; +#else + uint64_t _suspend_time; +#endif + int _suspend_period; + +protected: + void start_connection(); + void listen_for_connection(); + void make_connection(); + bool accept_connection(); + + void suspend(int short_ms, int long_ms=0, int threshold=0); + void suspend_on_disconnect(); + bool resume(); + bool suspend_period_expired(); + + bool accept_pending_connection(int ms); + + bool connected(); + bool poll_connection(int ms); + + static timeval timeval_from_ms(const uint32_t millis); + + bool wait_sock_readable(uint32_t timeout_ms, bool listener=false); + bool wait_sock_writable(uint32_t timeout_ms); + + void updateFIFO() override; + size_t dataOut(const void *buffer, size_t size) override; + +public: + BeckerSocket(); + virtual ~BeckerSocket(); + void begin(std::string host, int baud); + void end() override; + + void flushOutput() override; + + void setHost(std::string host, int port); +}; + +#endif // BECKERSOCKET_H diff --git a/lib/bus/drivewire/drivewire.cpp b/lib/bus/drivewire/drivewire.cpp index 62b7ff03f..f3abb7e13 100644 --- a/lib/bus/drivewire/drivewire.cpp +++ b/lib/bus/drivewire/drivewire.cpp @@ -32,6 +32,12 @@ static QueueHandle_t drivewire_evt_queue = NULL; #endif +#ifdef ESP_PLATFORM +#define DW_UART_DEVICE FN_UART_BUS +#else /* !ESP_PLATFORM */ +#define DW_UART_DEVICE Config.get_serial_port() +#endif /* ESP_PLATFORM */ + drivewireDload dload; // Host & client channel queues @@ -94,7 +100,7 @@ static void drivewire_intr_task(void *arg) void systemBus::op_jeff() { - fnDwCom.print("FUJINET"); + _port->print("FUJINET"); Debug_println("Jeff's op"); } @@ -126,11 +132,11 @@ void systemBus::op_readex() uint8_t rc = DISK_CTRL_STATUS_CLEAR; - drive_num = fnDwCom.read(); + drive_num = _port->read(); - lsn = fnDwCom.read() << 16; - lsn |= fnDwCom.read() << 8; - lsn |= fnDwCom.read(); + lsn = _port->read() << 16; + lsn |= _port->read() << 8; + lsn |= _port->read(); Debug_printf("OP_READ: DRIVE %3u - SECTOR %8lu\n", drive_num, lsn); @@ -152,11 +158,11 @@ void systemBus::op_readex() { size_t bytesrd; Debug_printf("op_readex: open successful %s\r\n", szNamedMount); - + memset(blk_buffer,0,MEDIA_BLOCK_SIZE); bytesrd = fread(blk_buffer,1,MEDIA_BLOCK_SIZE,pNamedObjFp); if (bytesrd!=MEDIA_BLOCK_SIZE || feof(pNamedObjFp)) - { + { Debug_printf("op_readex: closed named object %s\r\n",szNamedMount); fclose(pNamedObjFp); pNamedObjFp = NULL; @@ -167,12 +173,12 @@ void systemBus::op_readex() else { Debug_printf("op_readex: open failed %s\r\n", szNamedMount); - fnDwCom.write(0xF4); + _port->write(0xF4); return; } } else - { + { if (true==bDragon && drive_num>=5) drive_num = drive_num-5; Debug_printf("OP_READ: DRIVE %3u - SECTOR %8lu\n", drive_num, lsn); @@ -205,16 +211,16 @@ void systemBus::op_readex() blk_size = MEDIA_BLOCK_SIZE; use_media_buffer = false; } - + if (bDragon) { Debug_printf("dragon read\n"); if (d->read(lsn, sector_data)) { Debug_printf("Read error\n"); - fnDwCom.write(0xF4); - fnDwCom.flush(); - fnDwCom.flush_input(); + _port->write(0xF4); + _port->flushOutput(); + _port->discardInput(); return; } } @@ -241,11 +247,11 @@ void systemBus::op_readex() memset(blk_buffer, 0x00, blk_size); } // send sector data - fnDwCom.write(blk_buffer, blk_size); + _port->write(blk_buffer, blk_size); // receive checksum - c1 = (fnDwCom.read()) << 8; - c1 |= fnDwCom.read(); + c1 = (_port->read()) << 8; + c1 |= _port->read(); // test checksum if (rc == DISK_CTRL_STATUS_CLEAR) @@ -260,8 +266,8 @@ void systemBus::op_readex() } // finally, send the transaction status - fnDwCom.write(rc); - fnDwCom.flush(); + _port->write(rc); + _port->flushOutput(); } @@ -270,31 +276,31 @@ void systemBus::op_write() drivewireDisk *d = nullptr; uint16_t c1 = 0; - drive_num = fnDwCom.read(); + drive_num = _port->read(); - lsn = fnDwCom.read() << 16; - lsn |= fnDwCom.read() << 8; - lsn |= fnDwCom.read(); + lsn = _port->read() << 16; + lsn |= _port->read() << 8; + lsn |= _port->read(); - size_t s = fnDwCom.readBytes(sector_data, MEDIA_BLOCK_SIZE); + size_t s = _port->read(sector_data, MEDIA_BLOCK_SIZE); if (s != MEDIA_BLOCK_SIZE) { Debug_printv("Insufficient # of bytes for write, total recvd: %u", s); - fnDwCom.flush_input(); + _port->discardInput(); return; } // Todo handle checksum. - c1 = fnDwCom.read(); - c1 |= fnDwCom.read() << 8; + c1 = _port->read(); + c1 |= _port->read() << 8; drivewire_checksum(sector_data, MEDIA_BLOCK_SIZE); // if (c1 != c2) // { // Debug_printf("Checksum error\n"); - // fnDwCom.write(243); + // _port->write(243); // return; // } @@ -305,25 +311,25 @@ void systemBus::op_write() if (!d) { Debug_printv("Invalid drive #%3u", drive_num); - fnDwCom.write(0xF6); + _port->write(0xF6); return; } if (!d->device_active) { Debug_printv("Device not active."); - fnDwCom.write(0xF6); + _port->write(0xF6); return; } if (d->write(lsn, sector_data)) { Debug_print("Write error\n"); - fnDwCom.write(0xF5); + _port->write(0xF5); return; } - fnDwCom.write(0x00); // success + _port->write(0x00); // success } void systemBus::op_fuji() @@ -341,7 +347,7 @@ void systemBus::op_cpm() void systemBus::op_net() { // Get device ID - uint8_t device_id = (uint8_t)fnDwCom.read(); + uint8_t device_id = (uint8_t)_port->read(); // If device doesn't exist, create it. if (!_netDev.contains(device_id)) @@ -359,10 +365,10 @@ void systemBus::op_unhandled(uint8_t c) { Debug_printv("Unhandled opcode: %02x", c); - while (fnDwCom.available()) - Debug_printf("%02x ", fnDwCom.read()); + while (_port->available()) + Debug_printf("%02x ", _port->read()); - fnDwCom.flush_input(); + _port->discardInput(); } void systemBus::op_time() @@ -374,12 +380,12 @@ void systemBus::op_time() Debug_printf("Returning %02d/%02d/%02d %02d:%02d:%02d\n", now->tm_year, now->tm_mon, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); - fnDwCom.write(now->tm_year); - fnDwCom.write(now->tm_mon); - fnDwCom.write(now->tm_mday); - fnDwCom.write(now->tm_hour); - fnDwCom.write(now->tm_min); - fnDwCom.write(now->tm_sec); + _port->write(now->tm_year); + _port->write(now->tm_mon); + _port->write(now->tm_mday); + _port->write(now->tm_hour); + _port->write(now->tm_min); + _port->write(now->tm_sec); } void systemBus::op_init() @@ -390,13 +396,13 @@ void systemBus::op_init() void systemBus::op_serinit() { Debug_printv("OP_SERINIT"); - fnDwCom.read(); + _port->read(); } void systemBus::op_serterm() { Debug_printv("OP_SERTERM"); - fnDwCom.read(); + _port->read(); } void systemBus::op_dwinit() @@ -404,37 +410,37 @@ void systemBus::op_dwinit() Debug_printv("OP_DWINIT - Sending feature byte 0x%02x", DWINIT_FEATURES); #define OS9 1 #ifdef OS9 - fnDwCom.write(0x04); + _port->write(0x04); #else - fnDwCom.write(DWINIT_FEATURES); + _port->write(DWINIT_FEATURES); #endif } void systemBus::op_getstat() { - Debug_printv("OP_GETSTAT: 0x%02x 0x%02x", fnDwCom.read(),fnDwCom.read()); + Debug_printv("OP_GETSTAT: 0x%02x 0x%02x", _port->read(),_port->read()); } void systemBus::op_setstat() { - Debug_printv("OP_SETSTAT: 0x%02x 0x%02x", fnDwCom.read(),fnDwCom.read()); + Debug_printv("OP_SETSTAT: 0x%02x 0x%02x", _port->read(),_port->read()); } void systemBus::op_sergetstat() { - unsigned char vchan = fnDwCom.read(); - unsigned char code = fnDwCom.read(); + unsigned char vchan = _port->read(); + unsigned char code = _port->read(); Debug_printv("OP_SERGETSTAT: 0x%02x 0x%02x", vchan, code); } void systemBus::op_sersetstat() { - unsigned char vchan = fnDwCom.read(); - unsigned char code = fnDwCom.read(); + unsigned char vchan = _port->read(); + unsigned char code = _port->read(); Debug_printv("OP_SERSETSTAT: 0x%02x 0x%02x", vchan, code); if (code == 0x28) { for (int i = 0; i < 26; i++) { - fnDwCom.read(); + _port->read(); } } } @@ -454,16 +460,16 @@ void systemBus::op_serread() } } - fnDwCom.write(vchan); - fnDwCom.write(response); + _port->write(vchan); + _port->write(response); Debug_printv("OP_SERREAD: vchan $%02x - response $%02x\n", vchan, response); } void systemBus::op_serreadm() { - unsigned char vchan = fnDwCom.read(); - unsigned char count = fnDwCom.read(); + unsigned char vchan = _port->read(); + unsigned char count = _port->read(); // scan client channels for first that has available data for (vchan = 0; vchan < 16; vchan++) { @@ -472,7 +478,7 @@ void systemBus::op_serreadm() for (int i = 0; i < count; i++) { int response = outgoingChannel[vchan].front(); outgoingChannel[vchan].pop(); - fnDwCom.write(response); + _port->write(response); Debug_printv("OP_SERREADM: vchan $%02x - response $%02x\n", vchan, response); } break; @@ -482,8 +488,8 @@ void systemBus::op_serreadm() void systemBus::op_serwrite() { - unsigned char vchan = fnDwCom.read(); - unsigned char byte = fnDwCom.read(); + unsigned char vchan = _port->read(); + unsigned char byte = _port->read(); incomingChannel[vchan].push(byte); Debug_printv("OP_SERWRITE: vchan $%02x - byte $%02x\n", vchan, byte); } @@ -492,12 +498,12 @@ void systemBus::op_serwritem() { unsigned char vchan, count; - vchan = fnDwCom.read(); - fnDwCom.read(); // discard - count = fnDwCom.read(); + vchan = _port->read(); + _port->read(); // discard + count = _port->read(); for (int i = 0; i < count; i++) { - int byte = fnDwCom.read(); + int byte = _port->read(); incomingChannel[vchan].push(byte); Debug_printv("OP_SERWRITE: vchan $%02x - byte $%02x\n", vchan, byte); } @@ -505,7 +511,7 @@ void systemBus::op_serwritem() void systemBus::op_print() { - _printerdev->write(fnDwCom.read()); + _printerdev->write(_port->read()); } void systemBus::op_namedobj_mnt() @@ -513,12 +519,12 @@ void systemBus::op_namedobj_mnt() uint8_t namelen; uint16_t i; - namelen = fnDwCom.read(); + namelen = _port->read(); memset(szNamedMount,0,sizeof(szNamedMount)); for (i=0; iread(); - fnDwCom.write(0x01); + _port->write(0x01); Debug_printf("op_namedobj_mnt: %s\r\n", szNamedMount); // treat this event as a reset... @@ -528,7 +534,7 @@ void systemBus::op_namedobj_mnt() // Read and process a command frame from DRIVEWIRE void systemBus::_drivewire_process_cmd() { - int c = fnDwCom.read(); + int c = _port->read(); if (c < 0) { Debug_println("Failed to read cmd!"); @@ -540,7 +546,7 @@ void systemBus::_drivewire_process_cmd() if (c >= 0x80 && c <= 0x8F) { // handle FASTWRITE here int vchan = c & 0xF; - int byte = fnDwCom.read(); + int byte = _port->read(); incomingChannel[vchan].push(byte); } else { switch (c) @@ -668,46 +674,25 @@ void systemBus::service() } } - if (fnDwCom.available()) + if (_port->available()) _drivewire_process_cmd(); - fnDwCom.poll(1); - // dload.dload_process(); } -// Setup DRIVEWIRE bus -void systemBus::setup() -{ #ifdef ESP_PLATFORM - // Create a queue to handle parallel event from ISR - drivewire_evt_queue = xQueueCreate(10, sizeof(uint32_t)); - bDragon = false; - - // Start task - // xTaskCreate(drivewire_intr_task, "drivewire_intr_task", 2048, NULL, 10, NULL); - // xTaskCreatePinnedToCore(drivewire_intr_task, "drivewire_intr_task", 4096, this, 10, NULL, 0); - -#ifdef CONFIG_IDF_TARGET_ESP32S3 -// Configure UART to RP2040 -#ifdef FORCE_UART_BAUD - Debug_printv("FORCE_UART_BAUD set to %u", FORCE_UART_BAUD); - _drivewireBaud = FORCE_UART_BAUD; -#else - _drivewireBaud = 115200; -#endif - -#else - // Setup interrupt for cassette motor pin - gpio_config_t io_conf = { - .pin_bit_mask = (1ULL << PIN_CASS_MOTOR), // bit mask of the pins that you want to set +void systemBus::configureGPIO() +{ + // Setup interrupt for cassette motor pin + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << PIN_CASS_MOTOR), // bit mask of the pins that you want to set .mode = GPIO_MODE_INPUT, // set as input mode .pull_up_en = GPIO_PULLUP_DISABLE, // disable pull-up mode .pull_down_en = GPIO_PULLDOWN_ENABLE, // enable pull-down mode .intr_type = GPIO_INTR_POSEDGE // interrupt on positive edge - }; + }; - _cassetteDev = new drivewireCassette(); + _cassetteDev = new drivewireCassette(); // configure GPIO with the given settings gpio_config(&io_conf); @@ -726,60 +711,101 @@ void systemBus::setup() fnSystem.set_pin_mode(PIN_EPROM_A14, gpio_mode_t::GPIO_MODE_INPUT, SystemManager::pull_updown_t::PULL_NONE); fnSystem.set_pin_mode(PIN_EPROM_A15, gpio_mode_t::GPIO_MODE_INPUT, SystemManager::pull_updown_t::PULL_NONE); -#ifdef FORCE_UART_BAUD - Debug_printv("FORCE_UART_BAUD set to %u",FORCE_UART_BAUD); - _drivewireBaud = FORCE_UART_BAUD; -#else - if (fnSystem.digital_read(PIN_EPROM_A14) == DIGI_LOW && fnSystem.digital_read(PIN_EPROM_A15) == DIGI_LOW) + return; +} + +int systemBus::readBaudSwitch() +{ + if (fnSystem.digital_read(PIN_EPROM_A14) == DIGI_LOW + && fnSystem.digital_read(PIN_EPROM_A15) == DIGI_LOW) { - _drivewireBaud = 38400; //Coco1 ROM Image Debug_printv("A14 Low, A15 Low, 38400 baud"); + return 38400; //Coco1 ROM Image } - else if (fnSystem.digital_read(PIN_EPROM_A14) == DIGI_HIGH && fnSystem.digital_read(PIN_EPROM_A15) == DIGI_LOW) + + if (fnSystem.digital_read(PIN_EPROM_A14) == DIGI_HIGH + && fnSystem.digital_read(PIN_EPROM_A15) == DIGI_LOW) { - _drivewireBaud = 57600; //Coco2 ROM Image Debug_printv("A14 High, A15 Low, 57600 baud"); + return 57600; //Coco2 ROM Image } - else if (fnSystem.digital_read(PIN_EPROM_A14) == DIGI_LOW && fnSystem.digital_read(PIN_EPROM_A15) == DIGI_HIGH) + + if (fnSystem.digital_read(PIN_EPROM_A14) == DIGI_LOW + && fnSystem.digital_read(PIN_EPROM_A15) == DIGI_HIGH) { - _drivewireBaud = 115200; //Coco3 ROM Image Debug_printv("A14 Low, A15 High, 115200 baud"); + return 115200; //Coco3 ROM Image } - else - { - _drivewireBaud = 57600; // Dragon - bDragon = true; - Debug_printv("A14 and A15 High, (DRAGON) 57600 baud"); - } -#endif /* FORCE_UART_BAUD */ + Debug_printv("A14 and A15 High, defaulting to 57600 baud"); + return 57600; //Default or no switch +} +#endif /* ESP_PLATFORM */ + +// Setup DRIVEWIRE bus +void systemBus::setup() +{ +#ifdef ESP_PLATFORM + // Create a queue to handle parallel event from ISR + drivewire_evt_queue = xQueueCreate(10, sizeof(uint32_t)); + bDragon = false; + +#ifdef CONFIG_IDF_TARGET_ESP32S3 + // Configure UART to RP2040 + #ifdef FORCE_UART_BAUD + Debug_printv("FORCE_UART_BAUD set to %u", FORCE_UART_BAUD); + _drivewireBaud = FORCE_UART_BAUD; + #else /* !FORCE_UART_BAUD */ + _drivewireBaud = 115200; + #endif /* FORCE_UART_BAUD */ + +#else /* ! CONFIG_IDF_TARGET_ESP32S3 */ + configureGPIO(); + #ifdef FORCE_UART_BAUD + Debug_printv("FORCE_UART_BAUD set to %u",FORCE_UART_BAUD); + _drivewireBaud = FORCE_UART_BAUD; + #else /* !FORCE_UART_BAUD */ + _drivewireBaud = readBaudSwitch(); + #endif /* FORCE_UART_BAUD */ #endif /* CONFIG_IDF_TARGET_ESP32S3 */ -#else +#else /* !ESP_PLATFORM */ // FujiNet-PC specific - fnDwCom.set_serial_port(Config.get_serial_port().c_str()); // UART _drivewireBaud = Config.get_serial_baud(); -#endif - fnDwCom.set_becker_host(Config.get_boip_host().c_str(), Config.get_boip_port()); // Becker - fnDwCom.set_drivewire_mode(Config.get_boip_enabled() ? DwCom::dw_mode::BECKER : DwCom::dw_mode::SERIAL); +#endif /* !ESP_PLATFORM */ + + if (Config.get_boip_enabled()) + { + _becker.begin(Config.get_boip_host(), _drivewireBaud); + _port = &_becker; + } + else + { + _serial.begin(ChannelConfig() + .baud(_drivewireBaud) + .deviceID(DW_UART_DEVICE) + .readTimeout(500) +#ifdef ESP_PLATFORM + .inverted(DW_UART_DEVICE == UART_NUM_2) +#endif /* ESP_PLATFORM */ + ); + _port = &_serial; + } - fnDwCom.begin(_drivewireBaud); - fnDwCom.flush_input(); + _port->discardInput(); Debug_printv("DRIVEWIRE MODE"); - szNamedMount[0]=(uint8_t)0; - pNamedObjFp = NULL; -// jeff hack to see if the S3 is getting serial data + // jeff hack to see if the S3 is getting serial data // Debug_println("now receiving data..."); // uint8_t b[] = {' '}; // while(1) // { - // while (fnDwCom.available()) + // while (_port->available()) // { - // fnDwCom.read(b,1); + // _port->read(b,1); // Debug_printf("%c\n",b[0]); // } // } -// end jeff hack + // end jeff hack } diff --git a/lib/bus/drivewire/drivewire.h b/lib/bus/drivewire/drivewire.h index 5581d1303..dbf3d5f6f 100644 --- a/lib/bus/drivewire/drivewire.h +++ b/lib/bus/drivewire/drivewire.h @@ -19,6 +19,9 @@ #ifndef COCO_H #define COCO_H +#include "BeckerSocket.h" +#include "UARTChannel.h" + #ifdef ESP32_PLATFORM #include #include @@ -26,41 +29,38 @@ #include #include -// fnUartBUS (Serial only) was replaced with fnDwCom (Serial|TCP/Becker) -//#include -#include "drivewire/dwcom/fnDwCom.h" #include "media.h" #define DRIVEWIRE_BAUDRATE 57600 /* Operation Codes */ -#define OP_NOP 0 +#define OP_NOP 0 #define OP_JEFF 0xA5 #define OP_SERREAD 'C' #define OP_SERREADM 'c' #define OP_SERWRITE 0xC3 #define OP_SERWRITEM 0x64 -#define OP_GETSTAT 'G' -#define OP_SETSTAT 'S' -#define OP_SERGETSTAT 'D' -#define OP_SERSETSTAT 'D'+128 -#define OP_READ 'R' -#define OP_READEX 'R'+128 -#define OP_WRITE 'W' -#define OP_REREAD 'r' -#define OP_REREADEX 'r'+128 -#define OP_REWRITE 'w' -#define OP_INIT 'I' -#define OP_SERINIT 'E' -#define OP_SERTERM 'E'+128 +#define OP_GETSTAT 'G' +#define OP_SETSTAT 'S' +#define OP_SERGETSTAT 'D' +#define OP_SERSETSTAT 'D'+128 +#define OP_READ 'R' +#define OP_READEX 'R'+128 +#define OP_WRITE 'W' +#define OP_REREAD 'r' +#define OP_REREADEX 'r'+128 +#define OP_REWRITE 'w' +#define OP_INIT 'I' +#define OP_SERINIT 'E' +#define OP_SERTERM 'E'+128 #define OP_DWINIT 'Z' -#define OP_TERM 'T' -#define OP_TIME '#' +#define OP_TERM 'T' +#define OP_TIME '#' #define OP_RESET3 0xF8 -#define OP_RESET2 0xFE -#define OP_RESET1 0xFF -#define OP_PRINT 'P' -#define OP_PRINTFLUSH 'F' +#define OP_RESET2 0xFE +#define OP_RESET1 0xFF +#define OP_PRINT 'P' +#define OP_PRINTFLUSH 'F' #define OP_VPORT_READ 'C' #define OP_FUJI 0xE2 #define OP_NET 0xE3 @@ -82,26 +82,26 @@ // struct dwTransferData // { -// int dw_protocol_vrsn; -// FILE *devpath; -// FILE *dskpath[4]; -// int cocoType; -// int baudRate; -// unsigned char lastDrive; -// uint32_t readRetries; -// uint32_t writeRetries; -// uint32_t sectorsRead; -// uint32_t sectorsWritten; -// unsigned char lastOpcode; -// unsigned char lastLSN[3]; -// unsigned char lastSector[256]; -// unsigned char lastGetStat; -// unsigned char lastSetStat; -// uint16_t lastChecksum; -// unsigned char lastError; -// FILE *prtfp; -// unsigned char lastChar; -// char prtcmd[80]; +// int dw_protocol_vrsn; +// FILE *devpath; +// FILE *dskpath[4]; +// int cocoType; +// int baudRate; +// unsigned char lastDrive; +// uint32_t readRetries; +// uint32_t writeRetries; +// uint32_t sectorsRead; +// uint32_t sectorsWritten; +// unsigned char lastOpcode; +// unsigned char lastLSN[3]; +// unsigned char lastSector[256]; +// unsigned char lastGetStat; +// unsigned char lastSetStat; +// uint16_t lastChecksum; +// unsigned char lastError; +// FILE *prtfp; +// unsigned char lastChar; +// char prtcmd[80]; // }; // EXTERN char device[256]; @@ -114,7 +114,6 @@ // EXTERN struct dwTransferData datapack; // EXTERN int interactive; - // This is here because the network protocol adapters speak this union cmdFrame_t { @@ -152,7 +151,7 @@ class virtualDevice cmdFrame_t cmdFrame; bool listen_to_type3_polls = false; - + // Optional shutdown/reboot cleanup routine virtual void shutdown(){}; @@ -185,6 +184,10 @@ struct drivewire_message_t class systemBus { private: + IOChannel *_port = nullptr; + UARTChannel _serial; + BeckerSocket _becker; + virtualDevice *_activeDev = nullptr; drivewireModem *_modemDev = nullptr; drivewireFuji *_fujiDev = nullptr; @@ -200,6 +203,11 @@ class systemBus void _drivewire_process_cmd(); void _drivewire_process_queue(); +#ifdef ESP_PLATFORM + void configureGPIO(); + int readBaudSwitch(); +#endif /* ESP_PLATFORM */ + /** * @brief Current Baud Rate */ @@ -318,9 +326,27 @@ class systemBus // I wish this codebase would make up its mind to use camel or snake casing. drivewireModem *get_modem() { return _modemDev; } + // Everybody thinks "oh I know how a serial port works, I'll just + // access it directly and bypass the bus!" ಠ_ಠ + size_t read(void *buffer, size_t length) { return _port->read(buffer, length); } + size_t read() { return _port->read(); } + size_t write(const void *buffer, size_t length) { return _port->write(buffer, length); } + size_t write(int n) { return _port->write(n); } + size_t available() { return _port->available(); } + void flushOutput() { _port->flushOutput(); } + #ifdef ESP32_PLATFORM QueueHandle_t qDrivewireMessages = nullptr; #endif + + /* BoIP things */ + void setHost(const char *host, int port) { _becker.setHost(host, port); } + void selectSerialPort(bool useSerial) { + if (useSerial) + _port = &_serial; + else + _port = &_becker; + } }; extern systemBus SYSTEM_BUS; diff --git a/lib/bus/drivewire/dwcom/dwbecker.cpp b/lib/bus/drivewire/dwcom/dwbecker.cpp deleted file mode 100644 index 4f7fed983..000000000 --- a/lib/bus/drivewire/dwcom/dwbecker.cpp +++ /dev/null @@ -1,866 +0,0 @@ -#ifdef BUILD_COCO - -#include "dwbecker.h" - -#include -#include -#include -#include "compat_string.h" -#include -#include // write(), read(), close() -#include // Error integer and strerror() function -#include // Contains file controls like O_RDWR - -#ifndef ESP_PLATFORM - -#if !defined(_WIN32) -# include -# include -#endif - -#ifndef MSG_NOSIGNAL -# define MSG_NOSIGNAL 0 -# if defined(__APPLE__) || defined(__MACH__) -// MSG_NOSIGNAL does not exists on older macOS, use SO_NOSIGPIPE -# define USE_SO_NOSIGPIPE -# endif -#endif - -#endif // !ESP_PLATFORM - -#include "../../include/debug.h" - -#include "fnSystem.h" -#include "fnWiFi.h" - - -#define DW_DEFAULT_BAUD 57600 - - -// Constructor -BeckerPort::BeckerPort() : - _host{0}, - _ip(IPADDR_NONE), - _port(BECKER_DEFAULT_PORT), - _baud(DW_DEFAULT_BAUD), // not used by Becker - _listening(true), - _fd(-1), - _listen_fd(-1), - _state(&BeckerStopped::getInstance()), - _errcount(0) -{} - -BeckerPort::~BeckerPort() -{ - end(); -} - -void BeckerPort::begin(int baud) -{ - if (_state != &BeckerStopped::getInstance()) - end(); - - _baud = baud; - - // listen or connect - start_connection(); -} - -void BeckerPort::end() -{ - // close sockets - if (_fd >= 0) - { - shutdown(_fd, 0); - closesocket(_fd); - _fd = -1; - } - if (_listen_fd >= 0) - { - closesocket(_listen_fd); - _listen_fd = -1; - Debug_printf("### BeckerPort stopped ###\n"); - } - - // wait a while, otherwise wifi may turn off too quickly (during shutdown) - fnSystem.delay(50); - - setState(BeckerStopped::getInstance()); -} - -/* Returns number of bytes available in receive buffer or -1 on error -*/ -int BeckerPort::available() -{ - // only in connected state - if (_state != &BeckerConnected::getInstance()) - return 0; - - // check if socket is still connected - if (!connected()) - { - // connection was closed or it has an error - suspend_on_disconnect(); - return 0; - } - -#if defined(_WIN32) - unsigned long count; - int res = ioctlsocket(_fd, FIONREAD, &count); - res = res != 0 ? -1 : count; -#else - int count; - int res = ioctl(_fd, FIONREAD, &count); - res = res < 0 ? -1 : count; -#endif - return res; -} - -/* Discards anything in the input buffer -*/ -void BeckerPort::flush_input() -{ - // only in connected state - if (_state != &BeckerConnected::getInstance()) - return; - - // waste all input data - uint8_t rxbuf[256]; - int avail; - while ((avail = available()) > 0) - { - recv(_fd, (char *)rxbuf, avail > sizeof(rxbuf) ? sizeof(rxbuf) : avail, 0); - } -} - -/* Clears input buffer and flushes out transmit buffer waiting at most - waiting MAX_FLUSH_WAIT_TICKS until all sends are completed -*/ -void BeckerPort::flush() -{ - // only in connected state - if (_state != &BeckerConnected::getInstance()) - return; - - wait_sock_writable(250); -} - -// specific to BeckerPort -void BeckerPort::set_host(const char *host, int port) -{ - if (host != nullptr) - strlcpy(_host, host, sizeof(_host)); - else - _host[0] = 0; - - _port = port; -} - -const char* BeckerPort::get_host(int &port) -{ - port = _port; - return _host; -} - -void BeckerPort::start_connection() -{ - if (_listening) - listen_for_connection(); - else - make_connection(); -} - -void BeckerPort::listen_for_connection() -{ - - // Wait for WiFi - if (!fnWiFi.connected()) - { - Debug_println("BeckerPort: No WiFi!"); - // suspend for 0.5 or 2 sec, depending on _errcount - suspend(1000, 5000, 5); - return; - } - - Debug_printf("Setting up BeckerPort: listening on %s:%d\n", _host, _port); - - // Create listening socket - _listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); - if (_listen_fd < 0) - { - Debug_printf("BeckerPort: failed to create socket: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - suspend(BECKER_SUSPEND_MS); - return; - } - - // Set socket option - int enable = 1; -#if defined(_WIN32) - if (setsockopt(_listen_fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &enable, sizeof(enable)) != 0) -#else - if (setsockopt(_listen_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) != 0) -#endif - { - Debug_printf("BeckerPort: setsockopt failed: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - closesocket(_listen_fd); - _listen_fd = -1; - suspend(BECKER_SUSPEND_MS); - return; - } - - // Local address to listen on - if (_host[0] == '\0' || !strcmp(_host, "*")) - { - _ip = IPADDR_ANY; - } - else - { - _ip = get_ip4_addr_by_name(_host); - if (_ip == IPADDR_NONE) - { - Debug_println("BeckerPort: failed to resolve host name"); - closesocket(_listen_fd); - _listen_fd = -1; - suspend(BECKER_SUSPEND_MS); - return; - } - } - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = _ip; - addr.sin_port = htons(_port); - - // Bind to listening address - if (bind(_listen_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) - { - Debug_printf("BeckerPort: bind failed: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - closesocket(_listen_fd); - _listen_fd = -1; - suspend(BECKER_SUSPEND_MS); - return; - } - - // Listen for incoming connection - if (listen(_listen_fd, 1) != 0) - { - Debug_printf("BeckerPort: listen failed: %d %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - closesocket(_listen_fd); - _listen_fd = -1; - suspend(BECKER_SUSPEND_MS); - return; - } - - // Set socket non-blocking - if (!compat_socket_set_nonblocking(_listen_fd)) - { - Debug_printf("BeckerPort: failed to set non-blocking mode: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - closesocket(_listen_fd); - _listen_fd = -1; - suspend(BECKER_SUSPEND_MS); - return; - } - - // Finally setup - _errcount = 0; // used by suspend() - setState(BeckerWaitConn::getInstance()); - Debug_printf("### BeckerPort accepting connections ###\n"); -} - -void BeckerPort::make_connection() -{ - - // Wait for WiFi - if (!fnWiFi.connected()) - { - Debug_println("BeckerPort: No WiFi!"); - // suspend for 0.5 or 2 sec, depending on _errcount - suspend(1000, 5000, 5); - return; - } - - Debug_printf("Setting up BeckerPort: connecting to %s:%d\n", _host, _port); - - // Create connection socket - _fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); - if (_fd < 0) - { - Debug_printf("BeckerPort: failed to create socket: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - suspend(BECKER_SUSPEND_MS); - return; - } - -#ifdef USE_SO_NOSIGPIPE - // Set NOSIGPIPE socket option (old macOS) - int enable = 1; - if (setsockopt(_fd, SOL_SOCKET, SO_NOSIGPIPE, (char *)&enable, sizeof(enable)) < 0) - { - Debug_printf("BeckerPort: setsockopt failed: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - suspend(BECKER_SUSPEND_MS); - return; - } -#endif - - // Set socket non-blocking - if (!compat_socket_set_nonblocking(_fd)) - { - Debug_printf("BeckerPort: failed to set non-blocking mode: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - suspend(BECKER_SUSPEND_MS); - return; - } - - // Remote address - if (_host[0] == '\0') - { - _ip = IPADDR_LOOPBACK; - } - else - { - _ip = get_ip4_addr_by_name(_host); - if (_ip == IPADDR_NONE) - { - Debug_println("BeckerPort: failed to resolve host name"); - suspend(BECKER_SUSPEND_MS); - return; - } - } - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = _ip; - addr.sin_port = htons(_port); - - // Connect to remote address - int res = connect(_fd, (struct sockaddr *)&addr, sizeof(addr)); - int err = compat_getsockerr(); - -#if defined(_WIN32) - if (res < 0 && err != WSAEWOULDBLOCK) -#else - if (res < 0 && err != EINPROGRESS) -#endif - { - Debug_printf("BeckerPort: connect failed: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - suspend(BECKER_SUSPEND_MS); - return; - } - - if (!wait_sock_writable(BECKER_CONNECT_TMOUT)) - { - Debug_printf("BeckerPort: socket not ready\n"); - suspend(BECKER_SUSPEND_MS); - return; - } - - // Finally setup - _errcount = 0; - setState(BeckerConnected::getInstance()); - Debug_print("### BeckerPort connected ###\n"); -} - - -bool BeckerPort::accept_pending_connection(int ms) -{ - // if listening socket has new connection accept it - return(wait_sock_readable(ms, true) && accept_connection()); -} - - -bool BeckerPort::accept_connection() -{ - struct sockaddr_in addr; - int as = sizeof(struct sockaddr_in); - - // Accept connection - _fd = accept(_listen_fd, (struct sockaddr *)&addr, (socklen_t *)&as); - if (_fd < 0) - { - Debug_printf("BeckerPort: accept failed: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - return false; - } - Debug_printf("BeckerPort: connection from: %s\r\n", inet_ntoa(addr.sin_addr)); - - // Set socket options - int val = 1; - if (setsockopt(_fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&val, sizeof(val)) < 0) - { - Debug_printf("BeckerPort warning: failed to set KEEPALIVE on socket\n"); - } - if (setsockopt(_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)) < 0) - { - Debug_printf("BeckerPort warning: failed to set NODELAY on socket\n"); - } - - // Set socket non-blocking - if (!compat_socket_set_nonblocking(_fd)) - { - Debug_printf("BeckerPort: failed to set non-blocking connection: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - shutdown(_fd, 0); - closesocket(_fd); - _fd = -1; - return false; - } - - // We are connected ! - Debug_print("### BeckerPort connected ###\n"); - setState(BeckerConnected::getInstance()); - return true; -} - -void BeckerPort::suspend(int short_ms, int long_ms, int threshold) -{ - if (_fd >= 0) - { - closesocket(_fd); - _fd = -1; - } - _errcount++; - _suspend_time = fnSystem.millis(); - _suspend_period = short_ms; - if (threshold > 0 && _errcount > threshold && long_ms > 0) - _suspend_period = long_ms; - Debug_printf("Suspending BeckerPort for %d ms\n", _suspend_period); - setState(BeckerSuspended::getInstance()); -} - -void BeckerPort::suspend_on_disconnect() -{ - if (_listening && _listen_fd >=0) - { - if (_fd >= 0) - { - closesocket(_fd); - _fd = -1; - } - // go directly into waiting for connection state - setState(BeckerWaitConn::getInstance()); - } - else - { - // wait before reconnecting - suspend(BECKER_SUSPEND_MS); - } -} - -bool BeckerPort::resume() -{ - // Debug_print("Resuming BeckerPort\n"); - if (_listening) - { - if (_listen_fd >= 0) - { - // go directly into waiting for connection state - setState(BeckerWaitConn::getInstance()); - return true; - } - - } - // listen or connect - start_connection(); - return (_state != &BeckerSuspended::getInstance()); -} - -bool BeckerPort::suspend_period_expired() -{ - return (fnSystem.millis() - _suspend_time > _suspend_period); -} - -bool BeckerPort::connected() -{ - uint8_t dummy; - bool con = false; - int res = recv(_fd, (char *)&dummy, 1, MSG_PEEK); - if (res > 0) - { - con = true; - } - else if (res == 0) - { - Debug_print("### BeckerPort disconnected ###\n"); - } - else - { - int err = compat_getsockerr(); - switch (err) - { -#if defined(_WIN32) - case WSAEWOULDBLOCK: -#else - case EWOULDBLOCK: - case ENOENT: // Caused by VFS -#endif - con = true; - break; - default: - Debug_printf("BeckerPort: connection error: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(err)); - break; - } - } - return con; -} - -bool BeckerPort::poll_connection(int ms) -{ - if (wait_sock_readable(ms) && !connected()) - { - // connection was closed or it has an error - suspend_on_disconnect(); - } - return false; -} - -timeval BeckerPort::timeval_from_ms(const uint32_t millis) -{ - timeval tv; - tv.tv_sec = millis / 1000; - tv.tv_usec = (millis - (tv.tv_sec * 1000)) * 1000; - return tv; -} - -size_t BeckerPort::do_read(uint8_t *buffer, size_t size) -{ - int result; - int to_recv; - int rxbytes = 0; - - while (rxbytes < size) - { - to_recv = size - rxbytes; - result = read_sock(buffer+rxbytes, to_recv); - if (result > 0) - rxbytes += result; - else // result <= 0 for disconnected or write error - break; - } - return rxbytes; -} - -ssize_t BeckerPort::do_write(const uint8_t *buffer, size_t size) -{ - int result; - int to_send; - int txbytes = 0; - - while (txbytes < size) - { - to_send = size - txbytes; - result = write_sock(buffer+txbytes, to_send); - if (result > 0) - txbytes += result; - else if (result < 0) // write error - break; - } - return txbytes; -} - -ssize_t BeckerPort::read_sock(const uint8_t *buffer, size_t size, uint32_t timeout_ms) -{ - if (!wait_sock_readable(timeout_ms)) - { - Debug_printf("BeckerPort: read_sock() TIMEOUT\n"); - return -1; - } - - ssize_t result = recv(_fd, (char *)buffer, size, 0); - if (result < 0) - { - Debug_printf("BeckerPort: read_sock() error: %d - %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - suspend_on_disconnect(); - } - else if (result == 0) - { - Debug_printf("BeckerPort disconnected\n"); - suspend_on_disconnect(); - } - return result; -} - -ssize_t BeckerPort::write_sock(const uint8_t *buffer, size_t size, uint32_t timeout_ms) -{ - if (!wait_sock_writable(timeout_ms)) - { - int err = compat_getsockerr(); -#if defined(_WIN32) - if (err == WSAETIMEDOUT) -#else - if (err == ETIMEDOUT) -#endif - { - Debug_printf("BeckerPort: write_sock() TIMEOUT\n"); - } - else - { - suspend_on_disconnect(); - } - return -1; - } - - ssize_t result = send(_fd, (char *)buffer, size, 0); - if (result < 0) - { - Debug_printf("BeckerPort write_sock() error %d: %s\n", - compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); - suspend_on_disconnect(); - } - return result; -} - -bool BeckerPort::wait_sock_readable(uint32_t timeout_ms, bool listener) -{ - timeval timeout_tv; - fd_set readfds; - int result; - int fd = listener ? _listen_fd : _fd; - - for(;;) - { - // Setup a select call to block for socket data or a timeout - timeout_tv = timeval_from_ms(timeout_ms); - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - result = select(fd + 1, &readfds, nullptr, nullptr, &timeout_tv); - - // select error - if (result < 0) - { - int err = compat_getsockerr(); -#if defined(_WIN32) - if (err == WSAEINTR) -#else - if (err == EINTR) -#endif - { - // TODO adjust timeout_tv - continue; - } - Debug_printf("BeckerPort: wait_sock_readable() select error %d: %s\n", err, compat_sockstrerror(err)); - return false; - } - - // select timeout - if (result == 0) - return false; - - // this shouldn't happen, if result > 0 our fd has to be in the list! - if (!FD_ISSET(fd, &readfds)) - { - Debug_println("BeckerPort: wait_sock_readable() unexpected select result"); - return false; - } - break; - } - return true; -} - -bool BeckerPort::wait_sock_writable(uint32_t timeout_ms) -{ - timeval timeout_tv; - fd_set writefds; - fd_set errfds; - int result; - - for(;;) - { - timeout_tv = timeval_from_ms(timeout_ms); - // select for write - FD_ZERO(&writefds); - FD_SET(_fd, &writefds); - // select for error too - FD_ZERO(&errfds); - FD_SET(_fd, &errfds); - - result = select(_fd + 1, nullptr, &writefds, &errfds, &timeout_tv); - - // select error - if (result < 0) - { - int err = compat_getsockerr(); -#if defined(_WIN32) - if (err == WSAEINTR) -#else - if (err == EINTR) -#endif - { - // TODO adjust timeout_tv - continue; - } - Debug_printf("BeckerPort wait_sock_writable() select error %d: %s\n", err, compat_sockstrerror(err)); - return false; - } - - // select timeout - if (result == 0) - { -#if defined(_WIN32) - int err = WSAETIMEDOUT; -#else - int err = ETIMEDOUT; -#endif - // set errno - compat_setsockerr(err); - return false; - } - // Check for error on socket - { - int sockerr; - socklen_t len = (socklen_t)sizeof(int); - // Store any socket error value in sockerr - int res = getsockopt(_fd, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &len); - if (res < 0) - { - // Failed to retrieve SO_ERROR - int err = compat_getsockerr(); - Debug_printf("getsockopt on fd %d, errno: %d - %s\n", _fd, err ,compat_sockstrerror(err)); - return false; - } - // Retrieved SO_ERROR and found that we have an error condition - if (sockerr != 0) - { - Debug_printf("socket error on fd %d, errno: %d - %s\n", _fd, sockerr, compat_sockstrerror(sockerr)); - // set errno - compat_setsockerr(sockerr); - return false; - } - } - //Debug_print("socket is ready for write\n"); - break; - } - return true; -} - -// -// Becker state handlers -// - -// Stopped state - -bool BeckerStopped::poll(BeckerPort *port, int ms) -{ -#ifndef ESP_PLATFORM - fnSystem.delay(ms); // be nice to CPU -#endif - return false; -} - -size_t BeckerStopped::read(BeckerPort *port, uint8_t *buffer, size_t size) -{ - // read timeout - fnSystem.delay(BECKER_IOWAIT_MS); - return 0; -} - -ssize_t BeckerStopped::write(BeckerPort *port, const uint8_t *buffer, size_t size) -{ - // write timeout - fnSystem.delay(BECKER_IOWAIT_MS); - return 0; -} - -// Suspended state - -bool BeckerSuspended::poll(BeckerPort *port, int ms) -{ - if (!port->suspend_period_expired()) - { - // still suspended -#ifndef ESP_PLATFORM - fnSystem.delay(ms); // be nice to CPU -#endif - return false; - } - // resume - return port->resume(); -} - -size_t BeckerSuspended::read(BeckerPort *port, uint8_t *buffer, size_t size) -{ - if (!port->suspend_period_expired()) - { - // still suspended, read timeout - fnSystem.delay(BECKER_IOWAIT_MS); - return 0; - } - // resume - if (port->resume()) - { - // connection was resumed, we can proceed with read - return port->getState()->read(port, buffer, size); - } - return 0; -} - -ssize_t BeckerSuspended::write(BeckerPort *port, const uint8_t *buffer, size_t size) -{ - if (!port->suspend_period_expired()) - { - // still suspended, read timeout - fnSystem.delay(BECKER_IOWAIT_MS); - return 0; - } - // resume - if (port->resume()) - { - // connection was resumed, we can proceed with write - return port->getState()->write(port, buffer, size); - } - return 0; -} - -// Waiting for connection - -bool BeckerWaitConn::poll(BeckerPort *port, int ms) -{ - return port->accept_pending_connection(ms); // true if new connection was accepted -} - -size_t BeckerWaitConn::read(BeckerPort *port, uint8_t *buffer, size_t size) -{ - if (port->accept_pending_connection(BECKER_IOWAIT_MS)) - { - // connection was accepted, we can proceed with read - return port->getState()->read(port, buffer, size); - } - return 0; -} - -ssize_t BeckerWaitConn::write(BeckerPort *port, const uint8_t *buffer, size_t size) -{ - if (port->accept_pending_connection(BECKER_IOWAIT_MS)) - { - // connection was accepted, we can proceed with write - return port->getState()->write(port, buffer, size); - } - return 0; -} - -// Connected - -bool BeckerConnected::poll(BeckerPort *port, int ms) -{ - return port->poll_connection(ms); -} - -size_t BeckerConnected::read(BeckerPort *port, uint8_t *buffer, size_t size) -{ - return port->do_read(buffer, size); -} - -ssize_t BeckerConnected::write(BeckerPort *port, const uint8_t *buffer, size_t size) -{ - return port->do_write(buffer, size); -} - -#endif // BUILD_COCO \ No newline at end of file diff --git a/lib/bus/drivewire/dwcom/dwbecker.h b/lib/bus/drivewire/dwcom/dwbecker.h deleted file mode 100644 index b0ebf238a..000000000 --- a/lib/bus/drivewire/dwcom/dwbecker.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef DWBECKER_H -#define DWBECKER_H - -#include -#include - -#include "dwport.h" -#include "fnDNS.h" - -#define BECKER_DEFAULT_PORT 65504 -#define BECKER_IOWAIT_MS 500 -#define BECKER_CONNECT_TMOUT 2000 -#define BECKER_SUSPEND_MS 5000 - -class BeckerPort; - -class BeckerState -{ -public: - virtual bool poll(BeckerPort *port, int ms) = 0; - virtual size_t read(BeckerPort *port, uint8_t *buffer, size_t size) = 0; - virtual ssize_t write(BeckerPort *port, const uint8_t *buffer, size_t size) = 0; - virtual ~BeckerState() {} -}; - -class BeckerStopped : public BeckerState -{ -public: - virtual bool poll(BeckerPort *port, int ms) override; - virtual size_t read(BeckerPort *port, uint8_t *buffer, size_t size) override; - virtual ssize_t write(BeckerPort *port, const uint8_t *buffer, size_t size) override; - static BeckerStopped& getInstance() { static BeckerStopped instance; return instance; } - -private: - BeckerStopped() {} - BeckerStopped(const BeckerStopped& other); - BeckerStopped& operator=(const BeckerStopped& other); -}; - -class BeckerWaitConn : public BeckerState -{ -public: - virtual bool poll(BeckerPort *port, int ms) override; - virtual size_t read(BeckerPort *port, uint8_t *buffer, size_t size) override; - virtual ssize_t write(BeckerPort *port, const uint8_t *buffer, size_t size) override; - static BeckerWaitConn& getInstance() { static BeckerWaitConn instance; return instance; } - -private: - BeckerWaitConn() {} - BeckerWaitConn(const BeckerWaitConn& other); - BeckerWaitConn& operator=(const BeckerWaitConn& other); -}; - -class BeckerConnected : public BeckerState -{ -public: - virtual bool poll(BeckerPort *port, int ms) override; - virtual size_t read(BeckerPort *port, uint8_t *buffer, size_t size) override; - virtual ssize_t write(BeckerPort *port, const uint8_t *buffer, size_t size) override; - static BeckerConnected& getInstance() { static BeckerConnected instance; return instance; } -private: - BeckerConnected() {} - BeckerConnected(const BeckerConnected& other); - BeckerConnected& operator=(const BeckerConnected& other); -}; - -class BeckerSuspended : public BeckerState -{ -public: - virtual bool poll(BeckerPort *port, int ms) override; - virtual size_t read(BeckerPort *port, uint8_t *buffer, size_t size) override; - virtual ssize_t write(BeckerPort *port, const uint8_t *buffer, size_t size) override; - static BeckerSuspended& getInstance() { static BeckerSuspended instance; return instance; } -private: - BeckerSuspended() {} - BeckerSuspended(const BeckerSuspended& other); - BeckerSuspended& operator=(const BeckerSuspended& other); -}; - - -class BeckerPort : public DwPort -{ -private: - char _host[64]; // TODO change to std::string - in_addr_t _ip; - uint16_t _port; - - uint32_t _baud; // not used by Becker - - // is waiting for connection (listening) or connecting to? - bool _listening; - - // file descriptors - int _fd; - int _listen_fd; - - // state machine handlers for poll(), read() and write() - BeckerState *_state; - - // error counter - int _errcount; -#ifdef ESP_PLATFORM - unsigned long _suspend_time; -#else - uint64_t _suspend_time; -#endif - int _suspend_period; - -protected: - void start_connection(); - void listen_for_connection(); - void make_connection(); - bool accept_connection(); - - void suspend(int short_ms, int long_ms=0, int threshold=0); - void suspend_on_disconnect(); - bool resume(); - bool suspend_period_expired(); - - bool accept_pending_connection(int ms); - - bool connected(); - bool poll_connection(int ms); - - static timeval timeval_from_ms(const uint32_t millis); - - size_t do_read(uint8_t *buffer, size_t size); - ssize_t do_write(const uint8_t *buffer, size_t size); - - ssize_t read_sock(const uint8_t *buffer, size_t size, uint32_t timeout_ms=BECKER_IOWAIT_MS); - ssize_t write_sock(const uint8_t *buffer, size_t size, uint32_t timeout_ms=BECKER_IOWAIT_MS); - - bool wait_sock_readable(uint32_t timeout_ms, bool listener=false); - bool wait_sock_writable(uint32_t timeout_ms); - -public: - BeckerPort(); - virtual ~BeckerPort(); - virtual void begin(int baud) override; - virtual void end() override; - - // mimic UARTManager, baudrate is not used by BeckerPort - virtual void set_baudrate(uint32_t baud) override { _baud = baud; } - virtual uint32_t get_baudrate() override { return _baud; } - - virtual int available() override; - virtual void flush() override; - virtual void flush_input() override; - - // keep BeckerPort alive - virtual bool poll(int ms) override { return _state->poll(this, ms); } - // read bytes into buffer - virtual size_t read(uint8_t *buffer, size_t size) override { return _state->read(this, buffer, size); } - // write buffer - virtual ssize_t write(const uint8_t *buffer, size_t size) override { return _state->write(this, buffer, size); } - - // specific to BeckerPort - void set_host(const char *host, int port); - const char* get_host(int &port); - - inline BeckerState* getState() const { return _state; } - void setState(BeckerState& state) { _state = &state; } - - // friends, state handlers - friend class BeckerStopped; - friend class BeckerWaitConn; - friend class BeckerConnected; - friend class BeckerSuspended; -}; - - - -#endif // DWBECKER_H diff --git a/lib/bus/drivewire/dwcom/dwport.cpp b/lib/bus/drivewire/dwcom/dwport.cpp deleted file mode 100644 index 9ceb32d26..000000000 --- a/lib/bus/drivewire/dwcom/dwport.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef BUILD_COCO - -#include "dwport.h" - -#endif // BUILD_COCO diff --git a/lib/bus/drivewire/dwcom/dwport.h b/lib/bus/drivewire/dwcom/dwport.h deleted file mode 100644 index 6a6cb445f..000000000 --- a/lib/bus/drivewire/dwcom/dwport.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef DWPORT_H -#define DWPORT_H - -#include -#include - -/* - * Abstraction of DriveWire port - * provides interface to basic functionality and signals - */ - -class DwPort -{ -public: - virtual void begin(int baud) = 0; - virtual void end() = 0; - virtual bool poll(int ms) = 0; - - virtual void set_baudrate(uint32_t baud) = 0; - virtual uint32_t get_baudrate() = 0; - - virtual int available() = 0; - virtual void flush() = 0; - virtual void flush_input() = 0; - - virtual size_t read(uint8_t *buffer, size_t size) = 0; // read bytes into buffer - virtual ssize_t write(const uint8_t *buffer, size_t size) = 0; // write buffer -}; - -#endif // DWPORT_H diff --git a/lib/bus/drivewire/dwcom/dwserial.cpp b/lib/bus/drivewire/dwcom/dwserial.cpp deleted file mode 100644 index fabe3dad8..000000000 --- a/lib/bus/drivewire/dwcom/dwserial.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifdef BUILD_COCO - -#include "dwserial.h" - -#include "../../include/debug.h" - -void SerialDwPort::begin(int baud) -{ - Debug_printf("SerialDwPort: begin @ %d\n", baud); - _uart.begin(baud); -} - -// read bytes into buffer -size_t SerialDwPort::read(uint8_t *buffer, size_t size) -{ - // for UARTManager there is separate read() and readBytes(uint8_t *buffer, size_t size) ... - // TODO is there any reason to do special call to UARTManager for single byte? - if (size == 1) - { - int b = _uart.read(); // single byte from UART - if (b < 0) - return 0; // error, 0 bytes was read - *buffer = b; - return 1; // 1 byte was read - } - return _uart.readBytes(buffer, size); -} - -ssize_t SerialDwPort::write(const uint8_t *buffer, size_t size) -{ - // for UART there is separate write(uint8_t b) and write(uint8_t *buffer, size_t size) ... - // TODO is there any reason to do special call to UARTManager for single byte? - if (size == 1) - { - return _uart.write(*buffer); // single byte to UART - } - return _uart.write(buffer, size); -} - -#endif // BUILD_COCO diff --git a/lib/bus/drivewire/dwcom/dwserial.h b/lib/bus/drivewire/dwcom/dwserial.h deleted file mode 100644 index 706fe67d1..000000000 --- a/lib/bus/drivewire/dwcom/dwserial.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef DWSERIAL_H -#define DWSERIAL_H - -#include - -#include "fnUART.h" -#include "dwport.h" - -/* - * Implementation of DriveWire Port using UART serial port - * wrapper around existing UARTManager - */ - -class SerialDwPort : public DwPort -{ -private: -#ifdef ESP_PLATFORM - UARTManager _uart = UARTManager(FN_UART_BUS); -#else - UARTManager _uart; -#endif -public: - SerialDwPort() {} - virtual void begin(int baud) override; - virtual void end() override { _uart.end(); } - virtual bool poll(int ms) override - { -#ifdef ESP_PLATFORM - return false; -#else - return _uart.poll(ms); -#endif - } - - virtual int available() override { return _uart.available(); } - virtual void flush() override { _uart.flush(); } - virtual void flush_input() override { _uart.flush_input(); } - - // read bytes into buffer - virtual size_t read(uint8_t *buffer, size_t size) override; - // write buffer - virtual ssize_t write(const uint8_t *buffer, size_t size) override; - - // specific to SerialDwPort/UART - void set_baudrate(uint32_t baud) override { _uart.set_baudrate(baud); } - uint32_t get_baudrate() override { return _uart.get_baudrate(); } -#ifndef ESP_PLATFORM - void set_port(const char *device) { _uart.set_port(device); } - const char* get_port() { return _uart.get_port(); } -#endif -}; - -#endif // DWSERIAL_H diff --git a/lib/bus/drivewire/dwcom/fnDwCom.cpp b/lib/bus/drivewire/dwcom/fnDwCom.cpp deleted file mode 100644 index ab80bb016..000000000 --- a/lib/bus/drivewire/dwcom/fnDwCom.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#ifdef BUILD_COCO - -#include "fnDwCom.h" - -#include "../../include/debug.h" -/* - * DriveWire Communication class - * (replacement for UARTManager fnUartBUS) - * It uses DwPort for data exchange. - * DwPort can be physical serial port (SerialDwPort) to communicate with real CoCo computer - * or Becker port (DriveWire over TCP) for use with CoCo Emulators - */ - -// global instance -DwCom fnDwCom; - -// ctor -DwCom::DwCom() : _dw_mode(dw_mode::SERIAL), _dwPort(&_serialDw) {} - -// read single byte -int DwCom::read() -{ - uint8_t byte; - int result = _dwPort->read(&byte, 1); - if (result < 1) - return -1; - return byte; -} - -// print utility functions - -size_t DwCom::_print_number(unsigned long n, uint8_t base) -{ - char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. - char *str = &buf[sizeof(buf) - 1]; - - *str = '\0'; - - // prevent crash if called with base == 1 - if(base < 2) - base = 10; - - do { - unsigned long m = n; - n /= base; - char c = m - base * n; - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while(n); - - return write(str); -} - -size_t DwCom::print(long n, int base) -{ - if(base == 0) { - return write(n); - } else if(base == 10) { - if(n < 0) { - // int t = print('-'); - int t = print("-"); - n = -n; - return _print_number(n, 10) + t; - } - return _print_number(n, 10); - } else { - return _print_number(n, base); - } -} - -size_t DwCom::print(unsigned long n, int base) -{ - if(base == 0) { - return write(n); - } else { - return _print_number(n, base); - } -} - -// specific to SerialPort -#ifndef ESP_PLATFORM -void DwCom::set_serial_port(const char *device) -{ - Debug_printf("DwCom::set_serial_port %s\n", device ? device : "NULL"); - _serialDw.set_port(device); -}; - -const char* DwCom::get_serial_port() -{ - return _serialDw.get_port(); -}; -#endif - -// specific to BeckerPort -void DwCom::set_becker_host(const char *host, int port) -{ - Debug_printf("DwCom::set_becker_host %s:%d\n", host ? host : "NULL", port); - _beckerDw.set_host(host, port); -} - -const char* DwCom::get_becker_host(int &port) -{ - return _beckerDw.get_host(port); -} - -void DwCom::set_drivewire_mode(dw_mode mode) -{ - Debug_printf("DwCom::set_drivewire_mode: %s\n", mode == dw_mode::BECKER ? "BECKER" : "SERIAL"); - _dw_mode = mode; - switch(mode) - { - case dw_mode::BECKER: - _dwPort = &_beckerDw; - break; - default: - _dwPort = &_serialDw; - } -} - -// toggle BeckerPort and SerialPort -void DwCom::reset_drivewire_port(dw_mode mode) -{ - uint32_t baud = get_baudrate(); - end(); - set_drivewire_mode(mode); - begin(baud); -} - -#endif // BUILD_COCO diff --git a/lib/bus/drivewire/dwcom/fnDwCom.h b/lib/bus/drivewire/dwcom/fnDwCom.h deleted file mode 100644 index 556a0458c..000000000 --- a/lib/bus/drivewire/dwcom/fnDwCom.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef FNDWCOM_H -#define FNDWCOM_H - -#include - -#include "dwport.h" -#include "dwbecker.h" -#include "dwserial.h" - -/* - * DriveWire Communication class - * (replacement for UARTManager fnUartBUS) - * It uses DwPort for data exchange. - * DwPort can be physical serial port (SerialDwPort) to communicate with real CoCo computer - * or Becker port (DriveWire over TCP) for use with CoCO Emulator - */ - -class DwCom -{ -public: - // supported DriveWire port types - enum dw_mode - { - SERIAL = 0, - BECKER - }; - -private: - dw_mode _dw_mode; - DwPort *_dwPort; - SerialDwPort _serialDw; - BeckerPort _beckerDw; - - size_t _print_number(unsigned long n, uint8_t base); - -public: - DwCom(); - void begin(int baud = 0) - { - if (baud) - _dwPort->begin(baud); - else - _dwPort->begin(get_baudrate()); // start with default build-in baudrate - } - - void end() { _dwPort->end(); } - - /* - * Poll the DriveWire port - * ms = milliseconds to wait for "port event" - * return true if port handling is needed - */ - bool poll(int ms) { return _dwPort->poll(ms); } - - // used only by serial port - void set_baudrate(uint32_t baud) { _dwPort->set_baudrate(baud); } - uint32_t get_baudrate() { return _dwPort->get_baudrate(); } - - int available() { return _dwPort->available(); } - - void flush() { _dwPort->flush(); } - void flush_input() { _dwPort->flush_input(); } - - // read bytes into buffer - size_t read(uint8_t *buffer, size_t length) { return _dwPort->read(buffer, length); } - // alias to read, mimic UARTManager - size_t readBytes(uint8_t *buffer, size_t length) { return _dwPort->read(buffer, length); } - - // write buffer - ssize_t write(const uint8_t *buffer, size_t size) { return _dwPort->write(buffer, size); } - // write C-string - ssize_t write(const char *str) { return _dwPort->write((const uint8_t *)str, strlen(str)); } - - // read single byte, mimic UARTManager - int read(); - // write single byte, mimic UARTManager - ssize_t write(uint8_t b) { return _dwPort->write(&b, 1); } - - // mimic UARTManager overloaded write functions - size_t write(unsigned long n) { return write((uint8_t)n); } - size_t write(long n) { return write((uint8_t)n); } - size_t write(unsigned int n) { return write((uint8_t)n); } - size_t write(int n) { return write((uint8_t)n); } - - // print utility functions (used by modem) - size_t print(const char *str) { return write(str); } - size_t print(std::string str) { return write(str.c_str()); } - size_t print(int n, int base = 10) { return print((long) n, base); } - size_t print(unsigned int n, int base = 10) { return print((unsigned long) n, base); } - size_t print(long n, int base = 10); - size_t print(unsigned long n, int base = 10); - - // specific to SerialDwPort -#ifndef ESP_PLATFORM - void set_serial_port(const char *device); - const char* get_serial_port(); -#endif - - // specific to BeckerPort - void set_becker_host(const char *host, int port); - const char* get_becker_host(int &port); - - // get/set DriveWire mode - dw_mode get_drivewire_mode() {return _dw_mode;} - void set_drivewire_mode(dw_mode mode); - - void reset_drivewire_port(dw_mode mode); -}; - -extern DwCom fnDwCom; - -#endif // FNDWCOM_H diff --git a/lib/bus/drivewire/dwprotocol.c b/lib/bus/drivewire/dwprotocol.c deleted file mode 100644 index b8ef446fc..000000000 --- a/lib/bus/drivewire/dwprotocol.c +++ /dev/null @@ -1,743 +0,0 @@ -// #include "drivewire.h" - -// void *DriveWireProcessor(void *data) -// { -// struct dwTransferData *dp = (struct dwTransferData *)data; - -// WinUpdate(window0, dp); - -// while (comRead(dp, &(dp->lastOpcode), 1) > 0) -// { -// fd_set rfds; -// struct timeval tv; -// char *timeString = NULL; - -// { - -// switch (dp->lastOpcode) -// { -// case OP_RESET1: -// case OP_RESET2: -// DoOP_RESET(dp); -// break; - -// case OP_INIT: -// DoOP_INIT(dp); -// break; - -// case OP_TERM: -// DoOP_TERM(dp); -// break; - -// case OP_REREAD: -// DoOP_REREAD(dp, "OP_REREAD"); -// break; - -// case OP_READ: -// DoOP_READ(dp, "OP_READ"); -// break; - -// case OP_REREADEX: -// DoOP_REREADEX(dp, "OP_REREADEX"); -// break; - -// case OP_READEX: -// DoOP_READEX(dp, "OP_READEX"); -// break; - -// case OP_WRITE: -// DoOP_WRITE(dp, "OP_WRITE"); -// break; - -// case OP_REWRITE: -// DoOP_REWRITE(dp, "OP_REWRITE"); -// break; - -// case OP_GETSTAT: -// DoOP_GETSTAT(dp); -// break; - -// case OP_SETSTAT: -// DoOP_SETSTAT(dp); -// break; - -// case OP_TIME: -// DoOP_TIME(dp); -// break; - -// case OP_PRINT: -// DoOP_PRINT(dp); -// break; - -// case OP_PRINTFLUSH: -// DoOP_PRINTFLUSH(dp); -// break; - -// case OP_VPORT_READ: -// DoOP_VPORT_READ(dp); -// break; - -// default: -// break; -// } - -// fflush(dp->dskpath[dp->lastDrive]); -// } - -// WinUpdate(window0, dp); -// } - -// return NULL; -// } - - -// void DoOP_INIT(struct dwTransferData *dp) -// { - -// logHeader(); -// fprintf(logfp, "OP_INIT\n"); - -// return; -// } - - -// void DoOP_TERM(struct dwTransferData *dp) -// { -// logHeader(); -// fprintf(logfp, "OP_TERM\n"); - -// return; -// } - - -// void DoOP_REWRITE(struct dwTransferData *dp, char *logStr) -// { -// /* 1. Increment retry counter */ -// dp->writeRetries++; - -// /* 2. Call on WRITE handler */ -// DoOP_WRITE(dp, logStr); - -// return; -// } - - -// void DoOP_WRITE(struct dwTransferData *dp, char *logStr) -// { -// u_char cocoChecksum[2]; -// u_char response = 0; - -// /* 1. Read in drive # and 3 byte LSN */ -// comRead(dp, &(dp->lastDrive), 1); -// comRead(dp, dp->lastLSN, 3); - -// /* 2. Read in 256 byte lastSector from CoCo */ -// comRead(dp, dp->lastSector, 256); - -// /* 3. Compute Checksum on sector received */ -// if (dp->dw_protocol_vrsn == 1) -// { -// dp->lastChecksum = computeCRC(dp->lastSector, 256); -// } -// else -// { -// dp->lastChecksum = computeChecksum(dp->lastSector, 256); -// } - -// /* 4. Read in 2 byte Checksum from CoCo */ -// comRead(dp, cocoChecksum, 2); - -// /* 5. Compare */ -// if (dp->lastChecksum != int2(cocoChecksum)) -// { -// response = 0xF3; - -// /* 4.1.1 Bad Checksum, ask CoCo to send again, and return */ - -// comWrite(dp, &response, 1); - -// if (logfp != NULL) -// { -// logHeader(); -// fprintf(logfp, "%s[%d] LSN[%d] CoCoSum[%d], ServerSum[%d]\n", logStr, dp->lastDrive, int3(dp->lastLSN), int2(cocoChecksum), dp->lastChecksum); -// } -// // printf("WARNING! myChecksum = %X, cocoChecksum = %X\n", dp->lastChecksum, int2(cocoChecksum)); - - -// return; -// } - -// /* 5. Good Checksum, send positive ACK */ -// comWrite(dp, &response, 1); - -// /* 6. Seek to LSN in DSK image */ -// if (seekSector(dp, int3(dp->lastLSN)) == 0) -// { -// /* 7. Write lastSector to DSK image */ -// writeSector(dp); - -// /* 8. Everything is ok, send an ok ack */ -// comWrite(dp, &response, 1); - -// /* 9. Increment sectorsWritten count */ -// dp->sectorsWritten++; -// } - -// return; -// } - - -// void DoOP_RESET(struct dwTransferData *dp) -// { -// int a; - -// /* 1. Reset counters and flags */ -// dp->lastDrive = 0; -// dp->readRetries = 0; -// dp->writeRetries = 0; -// dp->sectorsRead = 0; -// dp->sectorsWritten = 0; -// dp->lastOpcode = OP_RESET1; - -// for (a = 0; a < 3; a++) -// { -// dp->lastLSN[a] = 0; -// } - -// for (a = 0; a < 256; a++) -// { -// dp->lastSector[a] = 0; -// } - -// dp->lastGetStat = 255; -// dp->lastSetStat = 255; -// dp->lastChecksum = 0; -// dp->lastError = 0; - -// logHeader(); -// fprintf(logfp, "OP_RESET\n"); - -// /* Finally, sync disks. */ -// #if 0 -// closeDSK(dp, 0); -// closeDSK(dp, 1); -// closeDSK(dp, 2); -// closeDSK(dp, 3); - -// openDSK(dp, 0); -// openDSK(dp, 1); -// openDSK(dp, 2); -// openDSK(dp, 3); -// #endif - -// return; -// } - - -// void DoOP_REREAD(struct dwTransferData *dp, char *logStr) -// { -// /* 1. Increment retry counter */ -// dp->readRetries++; - -// /* 2. Call on READ handler */ -// DoOP_READ(dp, logStr); - -// return; -// } - - -// void DoOP_READ(struct dwTransferData *dp, char *logStr) -// { -// /* 1. Read in drive # and 3 byte LSN */ -// comRead(dp, &(dp->lastDrive), 1); -// comRead(dp, dp->lastLSN, 3); - -// /* 2. Seek to position in disk image based on LSN received */ -// if (seekSector(dp, int3(dp->lastLSN)) == 0) -// { -// /* 3. Read the lastSector at LSN */ -// readSector(dp); - -// /* 4. Get error value, if any */ -// dp->lastError = errno; - -// /* 5. Send error code to CoCo */ -// comWrite(dp, &(dp->lastError), 1); - -// if (dp->lastError == 0) -// { -// u_char cocosum[2]; - -// /* 5.1.1. No error - send lastSector to CoCo */ -// comWrite(dp, dp->lastSector, 256); - -// /* 5.1.2. Compute Checksum and send to CoCo */ -// if (dp->dw_protocol_vrsn == 1) -// { -// dp->lastChecksum = computeCRC(dp->lastSector, 256); -// } -// else -// { -// dp->lastChecksum = computeChecksum(dp->lastSector, 256); -// } -// cocosum[0] = dp->lastChecksum >> 8; -// cocosum[1] = dp->lastChecksum & 0xFF; - -// comWrite(dp, (void *)cocosum, 2); - -// /* 5.1.3. Increment sectorsRead count */ -// dp->sectorsRead++; - -// logHeader(); -// fprintf(logfp, "%s[%d] LSN[%d] CoCoSum[%d]\n", logStr, dp->lastDrive, int3(dp->lastLSN), int2(cocosum)); -// } -// } - -// return; -// } - - -// void DoOP_REREADEX(struct dwTransferData *dp, char *logStr) -// { -// /* 1. Increment retry counter */ -// dp->readRetries++; - -// /* 2. Call on READ handler */ -// DoOP_READEX(dp, logStr); - -// return; -// } - - -// void DoOP_READEX(struct dwTransferData *dp, char *logStr) -// { -// /* 1. Read in drive # and 3 byte LSN */ -// comRead(dp, &(dp->lastDrive), 1); -// comRead(dp, dp->lastLSN, 3); - -// /* 2. Seek to position in disk image based on LSN received */ -// if (seekSector(dp, int3(dp->lastLSN)) == 0) -// { -// /* 3. Read the lastSector at LSN */ -// readSector(dp); - -// /* 4. Get error value, if any */ -// dp->lastError = errno; - -// /* 5. Send the sector data to the CoCo */ -// comWrite(dp, dp->lastSector, 256); - -// /* 6. Read the checksum from the coco */ -// u_char cocosum[2]; - -// comRead(dp, cocosum, 2); - -// if (dp->lastError == 0) -// { -// u_char mysum[2]; - -// dp->lastChecksum = computeChecksum(dp->lastSector, 256); - -// mysum[0] = (dp->lastChecksum >> 8) & 0xFF; -// mysum[1] = (dp->lastChecksum << 0) & 0xFF; - -// if (cocosum[0] == mysum[0] && cocosum[1] == mysum[1]) -// { -// /* Increment sectorsRead count */ -// dp->sectorsRead++; - -// logHeader(); -// fprintf(logfp, "%s[%d] LSN[%d] CoCoSum[%d]\n", logStr, dp->lastDrive, int3(dp->lastLSN), int2(cocosum)); -// } - -// comWrite(dp, &(dp->lastError), 1); - -// } -// } - -// return; -// } - - - -// void DoOP_GETSTAT(struct dwTransferData *dp) -// { -// /* 1. Read in drive # and stat code */ -// comRead(dp, &(dp->lastDrive), 1); -// comRead(dp, &(dp->lastGetStat), 1); - -// logHeader(); -// fprintf(logfp, "OP_GETSTAT[%0d] Code[%s]\n", dp->lastDrive, getStatCode(dp->lastGetStat)); - -// return; -// } - - -// void DoOP_SETSTAT(struct dwTransferData *dp) -// { -// /* 1. Read in drive # and stat code */ -// comRead(dp, &(dp->lastDrive), 1); -// comRead(dp, &(dp->lastSetStat), 1); - -// logHeader(); -// fprintf(logfp, "OP_SETSTAT[%0d] Code[%s]\n", dp->lastDrive, getStatCode(dp->lastSetStat)); - -// return; -// } - - -// void DoOP_TIME(struct dwTransferData *dp) -// { -// time_t currentTime; -// struct tm *timepak; -// char p[1]; - - -// currentTime = time(NULL); - -// timepak = localtime(¤tTime); - -// p[0] = timepak->tm_year; -// comWrite(dp, (void *)p, 1); -// p[0] = timepak->tm_mon + 1; -// comWrite(dp, (void *)p, 1); -// p[0] = timepak->tm_mday; -// comWrite(dp, (void *)p, 1); -// p[0] = timepak->tm_hour; -// comWrite(dp, (void *)p, 1); -// p[0] = timepak->tm_min; -// comWrite(dp, (void *)p, 1); -// p[0] = timepak->tm_sec; -// comWrite(dp, (void *)p, 1); -// p[0] = timepak->tm_wday; -// comWrite(dp, (void *)p, 1); - -// logHeader(); -// fprintf(logfp, "OP_TIME\n"); - -// return; -// } - - -// void DoOP_PRINT(struct dwTransferData *dp) -// { -// comRead(dp, &dp->lastChar, 1); -// fwrite(&dp->lastChar, 1, 1, dp->prtfp); - -// logHeader(); -// fprintf(logfp, "OP_PRINT\n"); - -// return; -// } - - -// void DoOP_PRINTFLUSH(struct dwTransferData *dp) -// { -// char buff[128]; - -// fclose(dp->prtfp); -// sprintf(buff, "cat drivewire.prt %s\n", dp->prtcmd); -// system(buff); -// dp->prtfp = fopen("drivewire.prt", "w+"); // empty it - -// logHeader(); -// fprintf(logfp, "OP_PRINTFLUSH\n"); - -// return; -// } - - -// void DoOP_VPORT_READ(struct dwTransferData *dp) -// { -// logHeader(); -// fprintf(logfp, "OP_VPORT_READ\n"); -// comWrite(dp, (void *)"\x00\x00", 2); - -// return; -// } - - -// uint16_t computeChecksum(u_char *data, int numbytes) -// { -// uint16_t lastChecksum = 0x0000; - -// /* Check to see if numbytes is odd or even */ -// while (numbytes--) -// { -// lastChecksum += *(data++); -// } - -// return(lastChecksum); -// } - - -// uint16_t computeCRC(u_char *data, int numbytes) -// { -// uint16_t i, crc = 0; -// uint16_t *ptr = (uint16_t *)data; - -// while(--numbytes >= 0) -// { -// crc = crc ^ *ptr++ << 8; - -// for (i = 0; i < 8; i++) -// { -// if (crc & 0x8000) -// { -// crc = crc << 1 ^ 0x1021; -// } -// else -// { -// crc = crc << 1; -// } -// } -// } - -// return (crc & 0xFFFF); -// } - - -// int comWrite(struct dwTransferData *dp, void *data, int numbytes) -// { -// /* Slight delay */ -// //usleep(10); - -// fwrite(data, numbytes, 1, dp->devpath); -// // write(dp->devpath, data, numbytes); - -// return(errno); -// } - - -// int readSector(struct dwTransferData *dp) -// { -// fread(dp->lastSector, 1, 256, dp->dskpath[dp->lastDrive]); - -// return(errno); -// } - - -// int writeSector(struct dwTransferData *dp) -// { -// fwrite(dp->lastSector, 1, 256, dp->dskpath[dp->lastDrive]); - -// return(errno); -// } - - -// int seekSector(struct dwTransferData *dp, int sector) -// { -// if (dp->dskpath[dp->lastDrive] == NULL) -// { -// return -1; -// } - -// fseek(dp->dskpath[dp->lastDrive], sector * 256, SEEK_SET); - -// return(errno); -// } - - -// int comRead(struct dwTransferData *dp, void *data, int numbytes) -// { -// return fread(data, numbytes, 1, dp->devpath); -// // return read(dp->devpath, data, numbytes); -// } - - -// void comRaw(struct dwTransferData *dp) -// { -// struct termios io_mod; -// int pathid = dp->devpath->FD; - -// tcgetattr(pathid, &io_mod); -// #if defined(__sun) -// io_mod.c_iflag &= -// ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); -// io_mod.c_oflag &= ~OPOST; -// io_mod.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); -// io_mod.c_cflag &= ~(CSIZE|PARENB); -// io_mod.c_cflag |= CS8; - -// cfsetospeed(&io_mod, dp->baudRate); -// #else -// cfmakeraw(&io_mod); -// cfsetspeed(&io_mod, dp->baudRate); -// #endif - -// if (tcsetattr(pathid, TCSANOW, &io_mod) < 0) -// { -// perror("ioctl error"); -// } -// } - - - -// unsigned int int4(u_char *a) -// { -// return (unsigned int)( (((u_char)*a)<<24) + ((u_char)*(a+1)<<16) + ((u_char)*(a+2)<<8) + (u_char)*(a+3) ); -// } - - -// unsigned int int3(u_char *a) -// { -// return(unsigned int)( (((u_char)*a)<<16) + ((u_char)*(a+1)<<8) + (u_char)*(a+2) ); -// } - - -// unsigned int int2(u_char *a) -// { -// //#ifndef __BIG_ENDIAN__ -// // return(unsigned int)( (((u_char)*(a+1))<<8) + (u_char)*a ); -// //#else -// return(unsigned int)( (((u_char)*a)<<8) + (u_char)*(a+1) ); -// //#endif -// } - - -// unsigned int int1(u_char *a) -// { -// return(unsigned int)( ((u_char)*a) ); -// } - - -// void _int4(unsigned int a, u_char *b) -// { -// b[0] = ((a >> 24) & 0xFF); b[1] = ((a >> 16) & 0xFF); b[2] = ((a >> 8) & 0xFF); b[3] = (a & 0xFF); -// } - - -// void _int3(unsigned int a, u_char *b) -// { -// b[0] = ((a >> 16) & 0xFF); b[1] = ((a >> 8) & 0xFF); b[2] = (a & 0xFF); -// } - - -// void _int2(uint16_t a, u_char *b) -// { -// b[0] = ((a >> 8) & 0xFF); b[1] = (a & 0xFF); -// } - - -// void _int1(unsigned int a, u_char *b) -// { -// b[0] = (a & 0xFF); -// } - -// char *getStatCode(int statcode) -// { -// static char codeName[64]; - -// switch (statcode) -// { -// case 0x00: -// strcpy(codeName, "SS.Opt"); -// break; - -// case 0x02: -// strcpy(codeName, "SS.Size"); -// break; - -// case 0x03: -// strcpy(codeName, "SS.Reset"); -// break; - -// case 0x04: -// strcpy(codeName, "SS.WTrk"); -// break; - -// case 0x05: -// strcpy(codeName, "SS.Pos"); -// break; - -// case 0x06: -// strcpy(codeName, "SS.EOF"); -// break; - -// case 0x0A: -// strcpy(codeName, "SS.Frz"); -// break; - -// case 0x0B: -// strcpy(codeName, "SS.SPT"); -// break; - -// case 0x0C: -// strcpy(codeName, "SS.SQD"); -// break; - -// case 0x0D: -// strcpy(codeName, "SS.DCmd"); -// break; - -// case 0x0E: -// strcpy(codeName, "SS.DevNm"); -// break; - -// case 0x0F: -// strcpy(codeName, "SS.FD"); -// break; - -// case 0x10: -// strcpy(codeName, "SS.Ticks"); -// break; - -// case 0x11: -// strcpy(codeName, "SS.Lock"); -// break; - -// case 0x12: -// strcpy(codeName, "SS.VarSect"); -// break; - -// case 0x14: -// strcpy(codeName, "SS.BlkRd"); -// break; - -// case 0x15: -// strcpy(codeName, "SS.BlkWr"); -// break; - -// case 0x16: -// strcpy(codeName, "SS.Reten"); -// break; - -// case 0x17: -// strcpy(codeName, "SS.WFM"); -// break; - -// case 0x18: -// strcpy(codeName, "SS.RFM"); -// break; - -// case 0x1B: -// strcpy(codeName, "SS.Relea"); -// break; - -// case 0x1C: -// strcpy(codeName, "SS.Attr"); -// break; - -// case 0x1E: -// strcpy(codeName, "SS.RsBit"); -// break; - -// case 0x20: -// strcpy(codeName, "SS.FDInf"); -// break; - -// case 0x26: -// strcpy(codeName, "SS.DSize"); -// break; - -// case 255: -// strcpy(codeName, "None"); -// break; - -// default: -// strcpy(codeName, "???"); -// break; -// } - -// return(codeName); -// } \ No newline at end of file diff --git a/lib/bus/drivewire/dwwin.c b/lib/bus/drivewire/dwwin.c deleted file mode 100644 index 60feef66d..000000000 --- a/lib/bus/drivewire/dwwin.c +++ /dev/null @@ -1,285 +0,0 @@ -// #include "drivewire.h" - -// void WinInit(void) -// { -// if (interactive == false) -// { -// return; -// } - -// int y = 1; - -// initscr(); -// clear(); -// window0 = newwin(24, 80, 0, 0); - -// if (window0 == NULL) -// { -// printf("window must be at least 80x24!\n"); -// exit(0); -// } - -// wattron(window0, A_STANDOUT); -// wprintw(window0, "DriveWire Server v%d.%d (C) 2009 Boisy G. Pitre", REV_MAJOR, REV_MINOR); -// wattroff(window0, A_STANDOUT); - - -// WinSetup(window0); -// } - - -// void WinSetup(WINDOW *window) -// { -// if (interactive == false) -// { -// return; -// } - -// int y = 2; - -// wmove(window, y++, 1); -// wprintw(window, "Last OpCode :"); -// wmove(window, y++, 1); -// wprintw(window, "Sectors Read :"); -// wmove(window, y++, 1); -// wprintw(window, "Sectors Written :"); -// wmove(window, y++, 1); -// wprintw(window, "Last LSN :"); -// wmove(window, y++, 1); -// wprintw(window, "Read Retries :"); -// wmove(window, y++, 1); -// wprintw(window, "Write Retries :"); -// wmove(window, y++, 1); -// wprintw(window, "%% Good Reads :"); -// wmove(window, y++, 1); -// wprintw(window, "%% Good Writes :"); -// wmove(window, y++, 1); -// wprintw(window, "Last GetStat :"); -// wmove(window, y++, 1); -// wprintw(window, "Last SetStat :"); -// y++; -// wmove(window, y++, 1); -// wprintw(window, "CoCo Type :"); -// wmove(window, y++, 1); -// wprintw(window, "Serial Port :"); -// wmove(window, y++, 1); -// wprintw(window, "DriveWire Mode :"); -// wmove(window, y++, 1); -// wprintw(window, "Print Command :"); -// y++; -// wmove(window, y++, 1); -// wprintw(window, "Disk 0 :"); -// wmove(window, y++, 1); -// wprintw(window, "Disk 1 :"); -// wmove(window, y++, 1); -// wprintw(window, "Disk 2 :"); -// wmove(window, y++, 1); -// wprintw(window, "Disk 3 :"); - -// y++; -// wmove(window, y++, 1); - -// wattron(window, A_STANDOUT); -// wprintw(window, "[0-3] Disk [C]oCo [P]ort [R]eset [M]ode [L]Print [Q]uit"); -// wattroff(window, A_STANDOUT); - -// /* 2. Refresh */ -// wrefresh(window); - -// return; -// } - - -// void WinUpdate(WINDOW *window, struct dwTransferData *dp) -// { -// if (interactive == false) -// { -// return; -// } - -// int x = 20; -// int y = 2; -// int i; - -// if (updating == 1) -// { -// return; -// } - -// wmove(window, y++, x); -// wclrtoeol(window); -// switch (dp->lastOpcode) -// { -// case OP_NOP: -// wprintw(window, "OP_NOP"); -// break; - -// case OP_INIT: -// wprintw(window, "OP_INIT"); -// break; - -// case OP_READ: -// wprintw(window, "OP_READ"); -// break; - -// case OP_READEX: -// wprintw(window, "OP_READEX"); -// break; - -// case OP_WRITE: -// wprintw(window, "OP_WRITE"); -// break; - -// case OP_REREAD: -// wprintw(window, "OP_REREAD"); -// break; - -// case OP_REREADEX: -// wprintw(window, "OP_REREADEX"); -// break; - -// case OP_REWRITE: -// wprintw(window, "OP_REWRITE"); -// break; - -// case OP_TERM: -// wprintw(window, "OP_TERM"); -// break; - -// case OP_RESET1: -// case OP_RESET2: -// wprintw(window, "OP_RESET"); -// break; - -// case OP_GETSTAT: -// wprintw(window, "OP_GETSTAT"); -// break; - -// case OP_SETSTAT: -// wprintw(window, "OP_SETSTAT"); -// break; - -// case OP_TIME: -// wprintw(window, "OP_TIME"); -// break; - -// case OP_PRINT: -// wprintw(window, "OP_PRINT"); -// break; - -// case OP_PRINTFLUSH: -// wprintw(window, "OP_PRINTFLUSH"); -// break; - -// default: -// wprintw(window, "UNKNOWN (%d)", dp->lastOpcode); -// break; -// } - -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, "%d", dp->sectorsRead); -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, "%d", dp->sectorsWritten); -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, "%d", int3(dp->lastLSN)); -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, "%d", dp->readRetries); -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, "%d", dp->writeRetries); -// wmove(window, y++, x); wclrtoeol(window); -// if (dp->sectorsRead + dp->readRetries == 0) -// { -// wprintw(window, "0%%"); -// } -// else -// { -// float percent = ((float)dp->sectorsRead / ((float)dp->sectorsRead + (float)dp->readRetries)) * 100; -// wprintw(window, "%3.3f%%", percent); -// } -// wmove(window, y++, x); wclrtoeol(window); -// if (dp->sectorsWritten + dp->writeRetries == 0) -// { -// wprintw(window, "0%%"); -// } -// else -// { -// float percent = ((float)dp->sectorsWritten / ((float)dp->sectorsWritten + (float)dp->writeRetries)) * 100; -// wprintw(window, "%3.3f%%", percent); -// } -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, "$%02X (%s)", dp->lastGetStat, getStatCode(dp->lastGetStat)); -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, "$%02X (%s)", dp->lastSetStat, getStatCode(dp->lastSetStat)); -// wmove(window, y++, x); wclrtoeol(window); -// wmove(window, y++, x); wclrtoeol(window); -// switch (dp->cocoType) -// { -// case 3: -// if (dp->dw_protocol_vrsn == 3) -// { -// wprintw(window, "%s", "CoCo 3 (115200 baud)"); -// } -// else -// { -// wprintw(window, "%s", "CoCo 3 (57600 baud)"); -// } -// break; - -// case 2: -// if (dp->dw_protocol_vrsn == 3) -// { -// wprintw(window, "%s", "CoCo 2 (57600 baud)"); -// } -// else -// { -// wprintw(window, "%s", "CoCo 1/2 (38400 baud)"); -// } -// break; -// } -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, "%s", device); -// wmove(window, y++, x); wclrtoeol(window); -// switch (dp->dw_protocol_vrsn) -// { -// case 3: -// wprintw(window, "3.0"); -// break; -// case 2: -// wprintw(window, "2.0"); -// break; -// case 1: -// wprintw(window, "1.0"); -// break; -// } - -// wclrtoeol(window); - -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, dp->prtcmd); - -// wmove(window, y++, x); wclrtoeol(window); - -// for (i = 0; i < 4; i++) -// { -// wmove(window, y++, x); wclrtoeol(window); -// wprintw(window, "%s", dskfile[i]); -// } - -// /* 2. Refresh */ -// wrefresh(window); - -// return; -// } - - -// void WinTerm(void) -// { -// if (interactive == false) -// { -// return; -// } - -// endwin(); - -// return; -// } \ No newline at end of file diff --git a/lib/bus/rs232/rs232.cpp b/lib/bus/rs232/rs232.cpp index 7243cddc4..102dfa52a 100755 --- a/lib/bus/rs232/rs232.cpp +++ b/lib/bus/rs232/rs232.cpp @@ -16,6 +16,12 @@ #include "utils.h" #include +#ifdef ESP_PLATFORM +#define SERIAL_DEVICE FN_UART_BUS +#else /* !ESP_PLATFORM */ +#define SERIAL_DEVICE Config.get_serial_port() +#endif /* ESP_PLATFORM */ + // Helper functions outside the class defintions uint16_t virtualDevice::rs232_get_aux16_lo() @@ -72,7 +78,7 @@ void virtualDevice::bus_to_computer(uint8_t *buf, uint16_t len, bool err) // Write checksum SYSTEM_BUS.write(rs232_checksum(buf, len)); - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); } /* @@ -121,7 +127,7 @@ uint8_t virtualDevice::bus_to_peripheral(uint8_t *buf, unsigned short len) void virtualDevice::rs232_nak() { SYSTEM_BUS.write('N'); - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); Debug_println("NAK!"); } @@ -130,7 +136,7 @@ void virtualDevice::rs232_ack() { SYSTEM_BUS.write('A'); fnSystem.delay_microseconds(DELAY_T5); //? - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); Debug_println("ACK!"); } @@ -166,14 +172,14 @@ void systemBus::_rs232_process_cmd() { _modemDev->modemActive = false; Debug_println("Modem was active - resetting RS232 baud"); - _port.set_baudrate(_rs232Baud); + _port.setBaudrate(_rs232Baud); } // Read CMD frame cmdFrame_t tempFrame; memset(&tempFrame, 0, sizeof(tempFrame)); - if (_port.readBytes((uint8_t *)&tempFrame, sizeof(tempFrame)) != sizeof(tempFrame)) + if (_port.read((uint8_t *)&tempFrame, sizeof(tempFrame)) != sizeof(tempFrame)) { Debug_println("Timeout waiting for data after CMD pin asserted"); return; @@ -185,9 +191,11 @@ void systemBus::_rs232_process_cmd() tempFrame.device, tempFrame.comnd, tempFrame.aux1, tempFrame.aux2, tempFrame.aux3, tempFrame.aux4, tempFrame.cksum); +#if 0 && !defined(FUJINET_OVER_USB) // Wait for CMD line to raise again - while (fnSystem.digital_read(PIN_RS232_DTR) == DIGI_LOW) + while (dsrState()) vTaskDelay(1); +#endif /* FUJINET_OVER_USB */ uint8_t ck = rs232_checksum((uint8_t *)&tempFrame, sizeof(tempFrame) - sizeof(tempFrame.cksum)); // Calculate Checksum if (ck == tempFrame.cksum) @@ -225,28 +233,6 @@ void systemBus::_rs232_process_cmd() fnLedManager.set(eLed::LED_BUS, false); } -// Look to see if we have any waiting messages and process them accordingly -/* -void systemBus::_rs232_process_queue() -{ - rs232_message_t msg; - if (xQueueReceive(qRs232Messages, &msg, 0) == pdTRUE) - { - switch (msg.message_id) - { - case RS232MSG_DISKSWAP: - if (_fujiDev != nullptr) - _fujiDev->image_rotate(); - break; - case RS232MSG_DEBUG_TAPE: - if (_fujiDev != nullptr) - _fujiDev->debug_tape(); - break; - } - } -} -*/ - /* Primary RS232 serivce loop: * If MOTOR line asserted, hand RS232 processing over to the TAPE device @@ -267,11 +253,19 @@ void systemBus::service() return; // break! } +#if 0 && !defined(FUJINET_OVER_USB) // Go process a command frame if the RS232 CMD line is asserted - if (fnSystem.digital_read(PIN_RS232_DTR) == DIGI_LOW) + if (_port.dsrState()) { _rs232_process_cmd(); } +#else /* FUJINET_OVER_USB */ + // Go process a command frame if the RS232 CMD line is asserted + if (_port.available()) + { + _rs232_process_cmd(); + } +#endif /* FUJINET_OVER_USB */ // Go check if the modem needs to read data if it's active else if (_modemDev != nullptr && _modemDev->modemActive && Config.get_modem_enabled()) { @@ -281,7 +275,7 @@ void systemBus::service() // Neither CMD nor active modem, so throw out any stray input data { //Debug_println("RS232 Srvc Flush"); - _port.flush_input(); + _port.discardInput(); } // Handle interrupts from network protocols @@ -298,8 +292,10 @@ void systemBus::setup() Debug_printf("RS232 SETUP: Baud rate: %u\n",Config.get_rs232_baud()); // Set up UART - _port.begin(Config.get_rs232_baud()); +#ifndef FUJINET_OVER_USB + _port.begin(ChannelConfig().baud(Config.get_rs232_baud()).deviceID(SERIAL_DEVICE)); +#ifdef ESP_PLATFORM // // INT PIN // fnSystem.set_pin_mode(PIN_RS232_RI, gpio_mode_t::GPIO_MODE_OUTPUT_OD, SystemManager::pull_updown_t::PULL_UP); // fnSystem.digital_write(PIN_RS232_RI, DIGI_HIGH); @@ -321,12 +317,13 @@ void systemBus::setup() fnSystem.set_pin_mode(PIN_RS232_DSR,gpio_mode_t::GPIO_MODE_OUTPUT); fnSystem.digital_write(PIN_RS232_DSR,DIGI_LOW); - - // Create a message queue - qRs232Messages = xQueueCreate(4, sizeof(rs232_message_t)); +#endif /* ESP_PLATFORM */ +#else /* FUJINET_OVER_USB */ + _port.begin(); +#endif /* FUJINET_OVER_USB */ Debug_println("RS232 Setup Flush"); - _port.flush_input(); + _port.discardInput(); } // Add device to RS232 bus @@ -421,7 +418,7 @@ void systemBus::toggleBaudrate() // Debug_printf("Toggling baudrate from %d to %d\n", _rs232Baud, baudrate); _rs232Baud = baudrate; - _port.set_baudrate(_rs232Baud); + _port.setBaudrate(_rs232Baud); } int systemBus::getBaudrate() @@ -439,7 +436,7 @@ void systemBus::setBaudrate(int baud) Debug_printf("Changing baudrate from %d to %d\n", _rs232Baud, baud); _rs232Baud = baud; - _port.set_baudrate(baud); + _port.setBaudrate(baud); } // Set HRS232 index. Sets high speed RS232 baud and also returns that value. diff --git a/lib/bus/rs232/rs232.h b/lib/bus/rs232/rs232.h index 0d8e038e8..f3aa21330 100755 --- a/lib/bus/rs232/rs232.h +++ b/lib/bus/rs232/rs232.h @@ -1,9 +1,12 @@ #ifndef RS232_H #define RS232_H -#include "fnUART.h" +#include "UARTChannel.h" + +#ifdef ESP_PLATFORM #include #include +#endif /* ESP_PLATFORM */ #include @@ -217,7 +220,11 @@ class systemBus bool useUltraHigh = false; // Use fujinet derived clock. - UARTManager _port = UARTManager(FN_UART_BUS); +#if FUJINET_OVER_USB + ACMChannel _port; +#else /* ! FUJINET_OVER_USB */ + UARTChannel _port; +#endif /* FUJINET_OVER_USB */ void _rs232_process_cmd(); /* void _rs232_process_queue(); */ @@ -249,19 +256,18 @@ class systemBus rs232Printer *getPrinter() { return _printerdev; } rs232CPM *getCPM() { return _cpmDev; } - QueueHandle_t qRs232Messages = nullptr; bool shuttingDown = false; // TRUE if we are in shutdown process bool getShuttingDown() { return shuttingDown; }; // Everybody thinks "oh I know how a serial port works, I'll just // access it directly and bypass the bus!" ಠ_ಠ - size_t read(void *buffer, size_t length) { return _port.readBytes(buffer, length); } + size_t read(void *buffer, size_t length) { return _port.read(buffer, length); } size_t read() { return _port.read(); } size_t write(const void *buffer, size_t length) { return _port.write(buffer, length); } size_t write(int n) { return _port.write(n); } size_t available() { return _port.available(); } - void flush() { _port.flush(); } + void flushOutput() { _port.flushOutput(); } size_t print(int n, int base = 10) { return _port.print(n, base); } size_t print(const char *str) { return _port.print(str); } size_t print(const std::string &str) { return _port.print(str); } diff --git a/lib/bus/sio/siocom/netsio.cpp b/lib/bus/sio/NetSIO.cpp similarity index 66% rename from lib/bus/sio/siocom/netsio.cpp rename to lib/bus/sio/NetSIO.cpp index 40fc53550..837fea635 100644 --- a/lib/bus/sio/siocom/netsio.cpp +++ b/lib/bus/sio/NetSIO.cpp @@ -1,24 +1,15 @@ -#ifndef ESP_PLATFORM - #ifdef BUILD_ATARI -#include "netsio.h" -#include "netsio_proto.h" - -#include -#include -#include -#include "compat_string.h" -#include -#include // write(), read(), close() -#include // Error integer and strerror() function -#include // Contains file controls like O_RDWR - -#include "../../include/debug.h" - +#include "NetSIO.h" #include "fnSystem.h" #include "fnWiFi.h" +#include "../../include/debug.h" +#ifdef ITS_A_UNIX_SYSTEM_I_KNOW_THIS +#include +#endif /* ITS_A_UNIX_SYSTEM_I_KNOW_THIS */ + +# define SIOPORT_DEFAULT_BAUD 19200 /* alive response timeout in seconds * device sends in regular intervals (2 s) alive messages (NETSIO_ALIVE_REQUEST) to NetSIO HUB @@ -33,7 +24,7 @@ // #define ALIVE_TIMEOUT_MS 600000 // Constructor -NetSioPort::NetSioPort() : +NetSIO::NetSIO() : _host{0}, _ip(IPADDR_NONE), _port(NETSIO_PORT), @@ -43,33 +34,30 @@ NetSioPort::NetSioPort() : _initialized(false), _command_asserted(false), _motor_asserted(false), - _rxhead(0), - _rxtail(0), - _rxfull(false), _sync_request_num(-1), _sync_write_size(-1), _errcount(0), _credit(3) {} -NetSioPort::~NetSioPort() +NetSIO::~NetSIO() { end(); } -void NetSioPort::begin(int baud) +void NetSIO::begin(std::string host, int port, int baud) { - if (_initialized) + if (_initialized) { end(); } _baud = baud; _resume_time = 0; + setHost(host, port); _command_asserted = false; _motor_asserted = false; - rxbuffer_flush(); // Wait for WiFi int suspend_ms = _errcount < 5 ? 400 : 2000; @@ -78,33 +66,33 @@ void NetSioPort::begin(int baud) Debug_println("NetSIO: No WiFi!"); _errcount++; suspend(suspend_ms); - return; - } + return; + } // // Connect to hub // suspend_ms = _errcount < 5 ? 1000 : 5000; - Debug_printf("Setting up NetSIO (%s:%d)\n", _host, _port); + Debug_printf("Setting up NetSIO (%s:%d)\n", _host.c_str(), _port); _fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (_fd < 0) { - Debug_printf("Failed to create NetSIO socket: %d, \"%s\"\n", + Debug_printf("Failed to create NetSIO socket: %d, \"%s\"\n", compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); _errcount++; suspend(suspend_ms); - return; - } - - _ip = get_ip4_addr_by_name(_host); + return; + } + + _ip = get_ip4_addr_by_name(_host.c_str()); if (_ip == IPADDR_NONE) { Debug_println("Failed to resolve NetSIO host name"); _errcount++; suspend(suspend_ms); - return; + return; } // Set remote IP address (no real connection is created for UDP socket) @@ -116,11 +104,11 @@ void NetSioPort::begin(int baud) if (connect(_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { // should not happen (UDP) - Debug_printf("Failed to connect NetSIO socket: %d, \"%s\"\n", + Debug_printf("Failed to connect NetSIO socket: %d, \"%s\"\n", compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); _errcount++; suspend(suspend_ms); - return; + return; } #if defined(_WIN32) @@ -148,10 +136,10 @@ void NetSioPort::begin(int baud) // Set initialized. _initialized = true; _errcount = 0; - set_baudrate(baud); + setBaudrate(baud); } -void NetSioPort::end() +void NetSIO::end() { if (_fd >= 0) { @@ -165,26 +153,14 @@ void NetSioPort::end() _initialized = false; } -bool NetSioPort::poll(int ms) -{ - if (_initialized) - { - if (handle_netsio() > 0) - return true; - return (wait_sock_readable(ms)); - } - fnSystem.delay(ms); - return false; -} - -void NetSioPort::suspend(int ms) +void NetSIO::suspend(int ms) { Debug_printf("Suspending NetSIO for %d ms\n", ms); _resume_time = fnSystem.millis() + ms; end(); } -int NetSioPort::ping(int count, int interval_ms, int timeout_ms, bool fast) +int NetSIO::ping(int count, int interval_ms, int timeout_ms, bool fast) { uint8_t ping; uint64_t t1, t2; @@ -203,14 +179,14 @@ int NetSioPort::ping(int count, int interval_ms, int timeout_ms, bool fast) ping = NETSIO_PING_REQUEST; result = send(_fd, (char *)&ping, 1, 0); t1 = fnSystem.micros(); - do + do { wait_ms = timeout_ms - (fnSystem.micros() - t1) / 1000; if (result == 1 && wait_sock_readable(wait_ms)) { t2 = fnSystem.micros(); result = recv(_fd, (char *)&ping, 1, 0); - if (result == 1 && ping == NETSIO_PING_RESPONSE) + if (result == 1 && ping == NETSIO_PING_RESPONSE) rtt = (int)(t2 - t1); } wait_ms = timeout_ms - (fnSystem.micros() - t1) / 1000; @@ -219,7 +195,7 @@ int NetSioPort::ping(int count, int interval_ms, int timeout_ms, bool fast) if (rtt >= 0) { - Debug_printf("NetSIO ping %s time=%.3f ms\n", _host, (double)(rtt)/1000.0); + Debug_printf("NetSIO ping %s time=%.3f ms\n", _host.c_str(), (double)(rtt)/1000.0); rtt_sum += rtt; ok_count++; if (fast) @@ -229,7 +205,7 @@ int NetSioPort::ping(int count, int interval_ms, int timeout_ms, bool fast) } else { - Debug_printf("NetSIO ping %s timeout\n", _host); + Debug_printf("NetSIO ping %s timeout\n", _host.c_str()); if (i+1 < count && interval_ms - timeout_ms > 0) fnSystem.delay(interval_ms - timeout_ms); } @@ -238,50 +214,7 @@ int NetSioPort::ping(int count, int interval_ms, int timeout_ms, bool fast) return ok_count ? rtt_sum / ok_count : -1; } -bool NetSioPort::rxbuffer_empty() -{ - return (_rxhead == _rxtail && !_rxfull); -} - -bool NetSioPort::rxbuffer_put(uint8_t b) -{ - _rxbuf[_rxhead++] = b; - _rxhead %= sizeof(_rxbuf); - if (_rxfull) { - // tail byte was overwritten / lost - _rxtail = _rxhead; - return true; - } - _rxfull = (_rxhead == _rxtail); - return false; -} - -int NetSioPort::rxbuffer_get() -{ - int b; - if (rxbuffer_empty()) - return -1; - b = _rxbuf[_rxtail++]; - _rxtail %= sizeof(_rxbuf); - _rxfull = false; - return b; -} - -int NetSioPort::rxbuffer_available() -{ - int avail = _rxhead - _rxtail; - if ((avail < 0) || (avail == 0 && _rxfull)) - avail += sizeof(_rxbuf); - return avail; -} - -void NetSioPort::rxbuffer_flush() -{ - _rxtail = _rxhead; - _rxfull = false; -} - -bool NetSioPort::resume_test() +bool NetSIO::resume_test() { if (!_initialized) { @@ -291,15 +224,14 @@ bool NetSioPort::resume_test() if (_resume_time > fnSystem.millis()) return false; // time to resume - begin(_baud); + begin(_host, _port, _baud); } } return _initialized; } -bool NetSioPort::keep_alive() +bool NetSIO::keep_alive() { - ssize_t result; uint64_t ms = fnSystem.millis(); // if ALIVE_RATE_MS time passed since last alive request was sent @@ -319,14 +251,14 @@ bool NetSioPort::keep_alive() } // reconnect on ping response end(); - begin(_baud); + begin(_host, _port, _baud); } // if nothing received for longer than ALIVE_RATE_MS, keep sending alive requests at ALIVE_RATE_MS rate else if (ms - _alive_time >= ALIVE_RATE_MS) { _alive_request = ms; uint8_t alive = NETSIO_ALIVE_REQUEST; - result = send(_fd, (char *)&alive, 1, 0); + send(_fd, (char *)&alive, 1, 0); // Debug_printf("Alive %lu %ld\n", ms, result); } } @@ -334,7 +266,7 @@ bool NetSioPort::keep_alive() } /* read NetSIO message from socket and update internal variables */ -int NetSioPort::handle_netsio() +int NetSIO::handle_netsio() { uint8_t rxbuf[514]; // must be able to hold whole netsio datagram, i.e. >= rxbuffer_len+2 defined in netsio.atdevice uint8_t b; @@ -358,14 +290,13 @@ int NetSioPort::handle_netsio() case NETSIO_DATA_BYTE_SYNC: if (received >= 3) _sync_request_num = rxbuf[2]; - // [[fallthrough]]; // > No warning + [[fallthrough]]; case NETSIO_DATA_BYTE: b = rxbuf[1]; if (_baud_peer < _baud * 90 / 100 || _baud_peer > _baud * 110 / 100) b ^= (uint8_t)_baud_peer ^ (uint8_t)_baud; // corrupt byte - if (rxbuffer_put(b)) - Debug_println("NetSIO rxbuffer overrun"); + _fifo.push_back(b); break; case NETSIO_DATA_BLOCK: @@ -377,16 +308,15 @@ int NetSioPort::handle_netsio() b = rxbuf[i]; if (_baud_peer < _baud * 90 / 100 || _baud_peer > _baud * 110 / 100) b ^= (uint8_t)_baud_peer ^ (uint8_t)_baud; // corrupt byte - if (rxbuffer_put(b)) - Debug_println("NetSIO rxbuffer overrun"); + _fifo.push_back(b); } } break; case NETSIO_COMMAND_OFF_SYNC: - if (received >= 2) + if (received >= 2) _sync_request_num = rxbuf[1]; // sync request sequence number - // [[fallthrough]]; // > No warning + [[fallthrough]]; case NETSIO_COMMAND_OFF: _command_asserted = false; @@ -396,7 +326,7 @@ int NetSioPort::handle_netsio() _command_asserted = true; _sync_request_num = -1; // cancel any sync request _sync_write_size = -1; - rxbuffer_flush(); // flush any stray input data + _fifo.clear(); // flush any stray input data break; case NETSIO_MOTOR_OFF: @@ -437,7 +367,7 @@ int NetSioPort::handle_netsio() return received; } -timeval NetSioPort::timeval_from_ms(const uint32_t millis) +timeval NetSIO::timeval_from_ms(const uint32_t millis) { timeval tv; tv.tv_sec = millis / 1000; @@ -445,12 +375,12 @@ timeval NetSioPort::timeval_from_ms(const uint32_t millis) return tv; } -bool NetSioPort::wait_sock_readable(uint32_t timeout_ms) +bool NetSIO::wait_sock_readable(uint32_t timeout_ms) { timeval timeout_tv; fd_set readfds; int result; - + for(;;) { // Setup a select call to block for socket data or a timeout @@ -466,7 +396,7 @@ bool NetSioPort::wait_sock_readable(uint32_t timeout_ms) #if defined(_WIN32) if (err == WSAEINTR) #else - if (err == EINTR) + if (err == EINTR) #endif { // TODO adjust timeout_tv @@ -491,7 +421,7 @@ bool NetSioPort::wait_sock_readable(uint32_t timeout_ms) return true; } -bool NetSioPort::wait_sock_writable(uint32_t timeout_ms) +bool NetSIO::wait_sock_writable(uint32_t timeout_ms) { timeval timeout_tv; fd_set writefds; @@ -505,13 +435,13 @@ bool NetSioPort::wait_sock_writable(uint32_t timeout_ms) result = select(_fd + 1, nullptr, &writefds, nullptr, &timeout_tv); // select error - if (result < 0) + if (result < 0) { int err = compat_getsockerr(); #if defined(_WIN32) if (err == WSAEINTR) #else - if (err == EINTR) + if (err == EINTR) #endif { // TODO adjust timeout_tv @@ -526,7 +456,7 @@ bool NetSioPort::wait_sock_writable(uint32_t timeout_ms) return false; // this shouldn't happen, if result > 0 our fd has to be in the list! - if (!FD_ISSET(_fd, &writefds)) + if (!FD_ISSET(_fd, &writefds)) { Debug_println("NetSIO wait_sock_writable() unexpected select result"); return false; @@ -536,7 +466,7 @@ bool NetSioPort::wait_sock_writable(uint32_t timeout_ms) return true; } -ssize_t NetSioPort::write_sock(const uint8_t *buffer, size_t size, uint32_t timeout_ms) +ssize_t NetSIO::write_sock(const uint8_t *buffer, size_t size, uint32_t timeout_ms) { if (!wait_sock_writable(timeout_ms)) { @@ -547,26 +477,13 @@ ssize_t NetSioPort::write_sock(const uint8_t *buffer, size_t size, uint32_t time ssize_t result = send(_fd, (char *)buffer, size, 0); if (result < 0) { - Debug_printf("NetSIO write_sock() send error %d: %s\n", + Debug_printf("NetSIO write_sock() send error %d: %s\n", compat_getsockerr(), compat_sockstrerror(compat_getsockerr())); } return result; } -bool NetSioPort::wait_for_data(uint32_t timeout_ms) -{ - while (rxbuffer_empty()) - { - if (!wait_sock_readable(timeout_ms)) - return false; // timeout - handle_netsio(); - // TODO adjust timeout_ms - } - // data available for read - return true; -} - -bool NetSioPort::wait_for_credit(int needed) +bool NetSIO::wait_for_credit(int needed) { uint8_t txbuf[2]; txbuf[0] = NETSIO_CREDIT_STATUS; @@ -575,7 +492,7 @@ bool NetSioPort::wait_for_credit(int needed) // wait for credit while (needed > _credit) { - if (!_initialized) + if (!_initialized) return false; // disconnected // inform HUB we need more credit send(_fd, (char *)txbuf, sizeof(txbuf), 0); @@ -589,38 +506,20 @@ bool NetSioPort::wait_for_credit(int needed) return true; } -/* Discards anything in the input buffer -*/ -void NetSioPort::flush_input() -{ - if (_initialized) - rxbuffer_flush(); -} - -/* Clears input buffer and flushes out transmit buffer waiting at most +/* Flushes out transmit buffer waiting at most waiting MAX_FLUSH_WAIT_TICKS until all sends are completed */ -void NetSioPort::flush() +void NetSIO::flushOutput() { if (_initialized) { - flush_input(); wait_sock_writable(500); } } -/* Returns number of bytes available in receive buffer or -1 on error -*/ -int NetSioPort::available() -{ - if (rxbuffer_empty()) - handle_netsio(); - return rxbuffer_available(); -} - /* Changes baud rate */ -void NetSioPort::set_baudrate(uint32_t baud) +void NetSIO::setBaudrate(uint32_t baud) { Debug_printf("NetSIO set_baudrate: %d\n", baud); @@ -638,169 +537,35 @@ void NetSioPort::set_baudrate(uint32_t baud) _baud = baud; } -uint32_t NetSioPort::get_baudrate() +uint32_t NetSIO::getBaudrate() { return _baud; } -bool NetSioPort::command_asserted(void) -{ - // process NetSIO message, if any - handle_netsio(); - return _command_asserted; -} - -bool NetSioPort::motor_asserted(void) +bool NetSIO::motorAsserted(void) { handle_netsio(); return _motor_asserted; } -void NetSioPort::set_proceed(bool level) -{ - static int last_level = -1; // 0,1 or -1 for unknown - int new_level = level ? 0 : 1; - - if (!_initialized) - return; - if (last_level == new_level) - return; - - Debug_print(level ? "_" : "-"); - last_level = new_level; - - wait_for_credit(1); - uint8_t cmd = level ? NETSIO_PROCEED_ON : NETSIO_PROCEED_OFF; - write_sock(&cmd, 1); -} - -void NetSioPort::set_interrupt(bool level) -{ - static int last_level = -1; // 0,1 or -1 for unknown - int new_level = level ? 0 : 1; - - if (!_initialized) - return; - if (last_level == new_level) - return; - - Debug_print(level ? "\\" : "/"); - last_level = new_level; - - wait_for_credit(1); - uint8_t cmd = level ? NETSIO_INTERRUPT_ON : NETSIO_INTERRUPT_OFF; - write_sock(&cmd, 1); -} - -void NetSioPort::bus_idle(uint16_t ms) +void NetSIO::updateFIFO() { - uint8_t cmd[3]; - cmd[0] = NETSIO_BUS_IDLE; - cmd[1] = ms & 0xff; - cmd[2] = (ms >> 8) & 0xff; - - wait_for_credit(1); - write_sock(cmd, sizeof(cmd)); -} - - -/* Returns a single byte from the incoming stream -*/ -int NetSioPort::read(void) -{ - if (!_initialized) - return -1; - - if (!wait_for_data(500)) - { - Debug_println("NetSIO read() - TIMEOUT"); - return -1; - } - return rxbuffer_get(); -} - -/* Since the underlying Stream calls this Read() multiple times to get more than one -* character for ReadBytes(), we override with a single call to uart_read_bytes -*/ -size_t NetSioPort::read(uint8_t *buffer, size_t length) -{ - if (!_initialized) - return 0; - - if (_sync_request_num >= 0 && _sync_write_size >= 0) - { - // handle pending sync request - // send late ACK byte - send_sync_response(NETSIO_ACK_SYNC, _sync_ack_byte, _sync_write_size); - // no delay here, emulator is not running - // 850 us pre-ACK delay will be added by netsio.atdevice - } - - int result; - int rxbytes; - for (rxbytes=0; rxbytes= 0 && _sync_write_size >= 0) { - // done - break; - } - } - return rxbytes; -} - -/* write single byte via NetSIO */ -ssize_t NetSioPort::write(uint8_t c) -{ - uint8_t txbuf[2]; - - if (!_initialized) - return 0; - - if (_sync_request_num >= 0) - { - // handle pending sync request - if (_sync_write_size < 0) - { - // SYNC RESPONSE - // send byte (should be ACK/NAK) bundled in sync response - return send_sync_response(NETSIO_ACK_SYNC, c, 0); - } - else - { - // sio_late_ack() was not from whatever reason followed by bus_to_peripheral() - Debug_println("Warn: NetSIO late ACK without bus_to_peripheral"); + // handle pending sync request // send late ACK byte - send_sync_response(NETSIO_ACK_SYNC, _sync_ack_byte, _sync_write_size); + sendSyncResponse(NETSIO_ACK_SYNC, _sync_ack_byte, _sync_write_size); + // no delay here, emulator is not running + // 850 us pre-ACK delay will be added by netsio.atdevice } } - - - // DATA BYTE - - if (!wait_for_credit(1)) - return 0; - - // send byte as usually - txbuf[0] = NETSIO_DATA_BYTE; // byte command - txbuf[1] = c; // value - ssize_t result = write_sock(txbuf, sizeof(txbuf)); - - return (result > 0) ? 1 : 0; // amount of data bytes written + return; } -ssize_t NetSioPort::write(const uint8_t *buffer, size_t size) +size_t NetSIO::dataOut(const void *buffer, size_t size) { int result; int to_send; @@ -815,7 +580,7 @@ ssize_t NetSioPort::write(const uint8_t *buffer, size_t size) // send block to_send = ((size-txbytes) > sizeof(txbuf)-1) ? sizeof(txbuf)-1 : (size-txbytes); txbuf[0] = NETSIO_DATA_BLOCK; - memcpy(txbuf+1, buffer+txbytes, to_send); + memcpy(txbuf+1, ((uint8_t *)buffer)+txbytes, to_send); // ? calculate credit based on amount of data ? if (!wait_for_credit(1)) break; @@ -828,35 +593,31 @@ ssize_t NetSioPort::write(const uint8_t *buffer, size_t size) return txbytes; } -// specific to NetSioPort -void NetSioPort::set_host(const char *host, int port) +void NetSIO::setWriteSize(int write_size) { - if (host != nullptr) - strlcpy(_host, host, sizeof(_host)); - else - _host[0] = 0; - - _port = port; + _sync_write_size = write_size + 1; // data + checksum byte } -const char* NetSioPort::get_host(int &port) +void NetSIO::setHost(std::string host, int port) { - port = _port; - return _host; + _host = host; + _port = port; } -void NetSioPort::set_sync_ack_byte(int ack_byte) +void NetSIO::setSyncAckByte(int ack_byte) { _sync_ack_byte = ack_byte; _sync_write_size = 0; } -void NetSioPort::set_sync_write_size(int write_size) +void NetSIO::sendEmptySync() { - _sync_write_size = write_size; + if (_sync_request_num >= 0) + sendSyncResponse(NETSIO_EMPTY_SYNC); } -ssize_t NetSioPort::send_sync_response(uint8_t response_type, uint8_t ack_byte, uint16_t sync_write_size) +ssize_t NetSIO::sendSyncResponse(uint8_t response_type, uint8_t ack_byte, + uint16_t sync_write_size) { uint8_t txbuf[6]; @@ -877,12 +638,40 @@ ssize_t NetSioPort::send_sync_response(uint8_t response_type, uint8_t ack_byte, return (result > 0 && response_type != NETSIO_EMPTY_SYNC) ? 1 : 0; // amount of data bytes written } -void NetSioPort::send_empty_sync() +void NetSIO::busIdle(uint16_t ms) { - if (_sync_request_num >= 0) - send_sync_response(NETSIO_EMPTY_SYNC); + uint8_t cmd[3]; + cmd[0] = NETSIO_BUS_IDLE; + cmd[1] = ms & 0xff; + cmd[2] = (ms >> 8) & 0xff; + + wait_for_credit(1); + write_sock(cmd, sizeof(cmd)); } -#endif // BUILD_ATARI +void NetSIO::setProceed(bool level) +{ + static int last_level = -1; // 0,1 or -1 for unknown + int new_level = level ? 0 : 1; + + if (!_initialized) + return; + if (last_level == new_level) + return; + + Debug_print(level ? "_" : "-"); + last_level = new_level; -#endif // !ESP_PLATFORM \ No newline at end of file + wait_for_credit(1); + uint8_t cmd = level ? NETSIO_PROCEED_ON : NETSIO_PROCEED_OFF; + write_sock(&cmd, 1); +} + +bool NetSIO::commandAsserted(void) +{ + // process NetSIO message, if any + handle_netsio(); + return _command_asserted; +} + +#endif // BUILD_ATARI diff --git a/lib/bus/sio/NetSIO.h b/lib/bus/sio/NetSIO.h new file mode 100644 index 000000000..1868bfffc --- /dev/null +++ b/lib/bus/sio/NetSIO.h @@ -0,0 +1,118 @@ +#ifndef NETSIO_H +#define NETSIO_H + +#include "IOChannel.h" +#include "fnDNS.h" +#include + +#define NETSIO_DATA_BYTE 0x01 +#define NETSIO_DATA_BLOCK 0x02 + +#define NETSIO_FILL_BUFFER 0x02 +#define NETSIO_TRANSMITT_BUFFER 0x03 + +#define NETSIO_DATA_BYTE_SYNC 0x09 + +#define NETSIO_COMMAND_OFF 0x10 +#define NETSIO_COMMAND_ON 0x11 +#define NETSIO_COMMAND_OFF_SYNC 0x18 +#define NETSIO_MOTOR_OFF 0x20 +#define NETSIO_MOTOR_ON 0x21 +#define NETSIO_PROCEED_OFF 0x30 +#define NETSIO_PROCEED_ON 0x31 +#define NETSIO_INTERRUPT_OFF 0x40 +#define NETSIO_INTERRUPT_ON 0x41 + +#define NETSIO_SPEED_CHANGE 0x80 +#define NETSIO_SYNC_RESPONSE 0x81 +#define NETSIO_BUS_IDLE 0x88 + +#define NETSIO_DEVICE_DISCONNECT 0xC0 +#define NETSIO_DEVICE_CONNECT 0xC1 +#define NETSIO_PING_REQUEST 0xC2 +#define NETSIO_PING_RESPONSE 0xC3 +#define NETSIO_ALIVE_REQUEST 0xC4 +#define NETSIO_ALIVE_RESPONSE 0xC5 +#define NETSIO_CREDIT_STATUS 0xC6 +#define NETSIO_CREDIT_UPDATE 0xC7 + +#define NETSIO_WARM_RESET 0xFE +#define NETSIO_COLD_RESET 0xFF + + +#define NETSIO_EMPTY_SYNC 0x00 +#define NETSIO_ACK_SYNC 0x01 + +#define NETSIO_PORT 9997 + +class NetSIO : public IOChannel +{ +private: + std::string _host; + in_addr_t _ip; + uint16_t _port; + + uint32_t _baud; + uint32_t _baud_peer; + int _fd; + bool _initialized; + bool _command_asserted; + bool _motor_asserted; + + int _sync_request_num; // 0..255 sync request sequence number, -1 if sync is not requested + uint8_t _sync_ack_byte; // ACK byte to send with sync response + int _sync_write_size; // 0 .. no SIO write (from computer), > 0 .. expected bytes written + + // serial port error counter + int _errcount; + uint64_t _resume_time; + uint64_t _alive_time; // when last message was received + uint64_t _alive_request; // when last ALIVE request was sent + // flow control + int _credit; + +protected: + void suspend(int ms=5000); + bool resume_test(); + bool keep_alive(); + + int handle_netsio(); + static timeval timeval_from_ms(const uint32_t millis); + + bool wait_sock_readable(uint32_t timeout_ms); + bool wait_for_data(uint32_t timeout_ms); + bool wait_for_credit(int needed); + + bool wait_sock_writable(uint32_t timeout_ms); + ssize_t write_sock(const uint8_t *buffer, size_t size, uint32_t timeout_ms=500); + + void updateFIFO() override; + size_t dataOut(const void *buffer, size_t size) override; + +public: + NetSIO(); + virtual ~NetSIO(); + void begin(std::string host, int port, int baud); + void end() override; + + void setBaudrate(uint32_t baud); + uint32_t getBaudrate(); + + bool commandAsserted(); + bool motorAsserted(); + void setProceed(bool level); + void setInterrupt(bool level); + + void flushOutput() override; + int ping(int count=4, int interval_ms=1000, int timeout_ms=500, bool fast=true); + + void setWriteSize(int write_size); + void setHost(std::string host, int port); + void setSyncAckByte(int ack_byte); + void sendEmptySync(); + ssize_t sendSyncResponse(uint8_t response_type, uint8_t ack_byte=0, + uint16_t sync_write_size=0); + void busIdle(uint16_t ms); +}; + +#endif // NETSIO_H diff --git a/lib/bus/sio/sio.cpp b/lib/bus/sio/sio.cpp index c69129b9d..0bb6817ed 100755 --- a/lib/bus/sio/sio.cpp +++ b/lib/bus/sio/sio.cpp @@ -15,6 +15,12 @@ #include "led.h" #include "utils.h" +#ifdef ESP_PLATFORM +#define SIO_UART_DEVICE FN_UART_BUS +#else /* !ESP_PLATFORM */ +#define SIO_UART_DEVICE Config.get_serial_port() +#endif /* ESP_PLATFORM */ + // Helper functions outside the class defintions // Get requested buffer length from command frame @@ -62,7 +68,7 @@ void virtualDevice::bus_to_computer(uint8_t *buf, uint16_t len, bool err) // Write checksum SYSTEM_BUS.write(sio_checksum(buf, len)); - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); } // TODO apc: change return type to indicate valid/invalid checksum @@ -78,7 +84,7 @@ uint8_t virtualDevice::bus_to_peripheral(uint8_t *buf, unsigned short len) Debug_printf("<-SIO read %hu bytes\n", len); #ifndef ESP_PLATFORM - if (SYSTEM_BUS.get_sio_mode() == SioCom::sio_mode::NETSIO) + if (SYSTEM_BUS.isBoIP()) { SYSTEM_BUS.netsio_write_size(len); // set hint for NetSIO } @@ -120,7 +126,7 @@ uint8_t virtualDevice::bus_to_peripheral(uint8_t *buf, unsigned short len) void virtualDevice::sio_nak() { SYSTEM_BUS.write('N'); - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); #ifndef ESP_PLATFORM SYSTEM_BUS.set_command_processed(true); #endif @@ -132,7 +138,7 @@ void virtualDevice::sio_ack() { SYSTEM_BUS.write('A'); fnSystem.delay_microseconds(DELAY_T5); //? - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); #ifndef ESP_PLATFORM SYSTEM_BUS.set_command_processed(true); #endif @@ -143,7 +149,7 @@ void virtualDevice::sio_ack() #ifndef ESP_PLATFORM void virtualDevice::sio_late_ack() { - if (SYSTEM_BUS.get_sio_mode() == SioCom::sio_mode::NETSIO) + if (SYSTEM_BUS.isBoIP()) { SYSTEM_BUS.netsio_late_sync('A'); SYSTEM_BUS.set_command_processed(true); @@ -180,7 +186,7 @@ void virtualDevice::sio_high_speed() uint8_t hsd = SYSTEM_BUS.getHighSpeedIndex(); #else int index = SYSTEM_BUS.getHighSpeedIndex(); - uint8_t hsd = index == HSIO_DISABLED_INDEX ? 40 : (uint8_t)index; + uint8_t hsd = index == HSIO_INVALID_INDEX ? 40 : (uint8_t)index; #endif bus_to_computer((uint8_t *)&hsd, 1, false); } @@ -218,11 +224,11 @@ void systemBus::_sio_process_cmd() // Wait for CMD line to raise again #ifdef ESP_PLATFORM - while (fnSystem.digital_read(PIN_CMD) == DIGI_LOW) + while (commandAsserted()) fnSystem.yield(); #else int i = 0; - while (_port.command_asserted()) + while (commandAsserted()) { fnSystem.delay_microseconds(500); if (++i == 100) @@ -232,12 +238,12 @@ void systemBus::_sio_process_cmd() } } - int bytes_pending = _port.available(); + int bytes_pending = _port->available(); if (bytes_pending > 0) { Debug_printf("!!! Extra bytes pending (%d)\n", bytes_pending); // TODO use last 5 received bytes as command frame - // _port.flush_input(); + // _port->flush_input(); } #endif @@ -352,22 +358,13 @@ void systemBus::_sio_process_queue() */ void systemBus::service() { -#ifndef ESP_PLATFORM - // loop until all SIO "events" are processed - do - { -#endif // Check for any messages in our queue (this should always happen, even if any other special // modes disrupt normal SIO handling - should probably make a separate task for this) _sio_process_queue(); if (_udpDev != nullptr && _udpDev->udpstreamActive) { -#ifdef ESP_PLATFORM - if (fnSystem.digital_read(PIN_CMD) == DIGI_LOW) -#else - if (_port.command_asserted()) -#endif + if (commandAsserted()) { Debug_println("CMD Asserted, stopping UDP Stream"); _udpDev->sio_disable_udpstream(); @@ -375,21 +372,13 @@ void systemBus::service() else { _udpDev->sio_handle_udpstream(); -#ifdef ESP_PLATFORM return; // break! -#else - continue; -#endif } } else if (_cpmDev != nullptr && _cpmDev->cpmActive && Config.get_cpm_enabled()) { _cpmDev->sio_handle_cpm(); -#ifdef ESP_PLATFORM return; // break! -#else - continue; -#endif } // check if cassette is mounted and enabled first @@ -400,7 +389,7 @@ void systemBus::service() #ifdef ESP_PLATFORM if (fnSystem.digital_read(PIN_MTR) == DIGI_HIGH) // TODO: use cassette helper function for consistency? #else - if (_port.motor_asserted()) + if (motor_asserted()) #endif { if (_fujiDev->cassette()->is_active() == false) // keep this logic because motor line mode @@ -422,20 +411,12 @@ void systemBus::service() if (_fujiDev->cassette()->is_active() == true) // handle cassette data traffic { _fujiDev->cassette()->sio_handle_cassette(); // -#ifdef ESP_PLATFORM return; // break! -#else - continue; -#endif } } // Go process a command frame if the SIO CMD line is asserted -#ifdef ESP_PLATFORM - if (fnSystem.digital_read(PIN_CMD) == DIGI_LOW) -#else - if (_port.command_asserted()) -#endif + if (commandAsserted()) { #ifndef ESP_PLATFORM unsigned long startms = fnSystem.millis(); @@ -461,8 +442,8 @@ void systemBus::service() #ifdef ESP_PLATFORM SYSTEM_BUS.discardInput(); #else - if (_port.get_sio_mode() == SioCom::sio_mode::SERIAL) - _port.flush_input(); + if (!SYSTEM_BUS.isBoIP()) + _port->discardInput(); #endif } @@ -472,23 +453,11 @@ void systemBus::service() if (_netDev[i] != nullptr) _netDev[i]->sio_poll_interrupt(); } -#ifndef ESP_PLATFORM - // loop until all SIO "events" are processed - // true = SIO port needs handling - // false = no SIO "event" ocurred within interval - } while (_port.poll(1)); -#endif } -// Setup SIO bus -void systemBus::setup() -{ - Debug_println("SIO SETUP"); - #ifdef ESP_PLATFORM - // Set up UART - _port.begin(_sioBaud); - +void systemBus::configureGPIO() +{ // INT PIN fnSystem.set_pin_mode(PIN_INT, gpio_mode_t::GPIO_MODE_OUTPUT_OD, SystemManager::pull_updown_t::PULL_UP); fnSystem.digital_write(PIN_INT, DIGI_HIGH); @@ -496,19 +465,66 @@ void systemBus::setup() fnSystem.set_pin_mode(PIN_PROC, gpio_mode_t::GPIO_MODE_OUTPUT_OD, SystemManager::pull_updown_t::PULL_UP); fnSystem.digital_write(PIN_PROC, DIGI_HIGH); // MTR PIN - //fnSystem.set_pin_mode(PIN_MTR, PINMODE_INPUT | PINMODE_PULLDOWN); // There's no PULLUP/PULLDOWN on pins 34-39 fnSystem.set_pin_mode(PIN_MTR, gpio_mode_t::GPIO_MODE_INPUT); // CMD PIN - //fnSystem.set_pin_mode(PIN_CMD, PINMODE_INPUT | PINMODE_PULLUP); // There's no PULLUP/PULLDOWN on pins 34-39 - fnSystem.set_pin_mode(PIN_CMD, gpio_mode_t::GPIO_MODE_INPUT); + // configured by SerialSIO, not here // CKI PIN fnSystem.set_pin_mode(PIN_CKI, gpio_mode_t::GPIO_MODE_OUTPUT_OD); fnSystem.digital_write(PIN_CKI, DIGI_HIGH); // CKO PIN fnSystem.set_pin_mode(PIN_CKO, gpio_mode_t::GPIO_MODE_INPUT); + return; +} +#endif /* ESP_PLATFORM */ + +// Setup SIO bus +void systemBus::setup() +{ + Debug_println("SIO SETUP"); + +#ifdef ESP_PLATFORM + configureGPIO(); + // Create a message queue qSioMessages = xQueueCreate(4, sizeof(sio_message_t)); +#endif /* ESP_PLATFORM */ + + // Setup SIO ports: serial UART and NetSIO + if (Config.get_boip_enabled()) + { + _netsio.begin(Config.get_boip_host(), Config.get_boip_port(), _sioBaud); + _port = &_netsio; + } + else + { + _serial.begin(ChannelConfig() + .baud(_sioBaud) + .deviceID(SIO_UART_DEVICE) +#ifdef ESP_PLATFORM + .readTimeout(pdTICKS_TO_MS(200)) + .discardTimeout(0) +#endif /* ESP_PLATFORM */ + ); + +#ifdef ESP_PLATFORM + _commandPin = PIN_CMD; +#else /* ! ESP_PLATFORM */ + _commandPin = Config.get_serial_command(); +#ifdef UNUSED + _proceedPin = Config.get_serial_proceed(); +#endif /* UNUSED */ +#endif /* ESP_PLATFORM */ + + _port = &_serial; + } + +#ifdef UNUSED +#ifndef ESP_PLATFORM + _port->setInterrupt(false); + _port->setProceed(false); +#endif /* ESP_PLATFORM */ +#endif /* UNUSED */ // Set the initial HSIO index // First see if Config has read a value @@ -518,22 +534,7 @@ void systemBus::setup() else setHighSpeedIndex(_sioHighSpeedIndex); - _port.flush_input(); -#else - // Setup SIO ports: serial UART and NetSIO - _port.set_serial_port(Config.get_serial_port().c_str(), Config.get_serial_command(), Config.get_serial_proceed()); // UART - _port.set_netsio_host(Config.get_boip_host().c_str(), Config.get_boip_port()); // NetSIO - _port.set_sio_mode(Config.get_boip_enabled() ? SioCom::sio_mode::NETSIO : SioCom::sio_mode::SERIAL); - _port.begin(_sioBaud); - - _port.set_interrupt(false); - _port.set_proceed(false); - - // Set the initial HSIO index - setHighSpeedIndex(Config.get_general_hsioindex()); - - _port.flush_input(); -#endif + _port->discardInput(); } // Add device to SIO bus @@ -622,7 +623,7 @@ void systemBus::shutdown() } Debug_printf("All devices shut down.\n"); #ifndef ESP_PLATFORM - _port.end(); + _port->end(); #endif } @@ -634,14 +635,14 @@ void systemBus::toggleBaudrate() baudrate = _sioBaud == SIO_STANDARD_BAUDRATE ? _sioBaudUltraHigh : SIO_STANDARD_BAUDRATE; // Debug_printf("Toggling baudrate from %d to %d\n", _sioBaud, baudrate); - _sioBaud = baudrate; #ifndef ESP_PLATFORM - _port.flush_input(); - _port.flush(); + _port->discardInput(); + _port->flushOutput(); // hmm, calling flush() may not be enough to empty TX buffer fnSystem.delay_microseconds(2000); #endif - _port.set_baudrate(_sioBaud); + + setBaudrate(baudrate); } int systemBus::getBaudrate() @@ -659,7 +660,12 @@ void systemBus::setBaudrate(int baud) Debug_printf("Changing baudrate from %d to %d\n", _sioBaud, baud); _sioBaud = baud; - _port.set_baudrate(baud); + + // Yah this looks stupid but C++ doesn't do true polymorphism + if (isBoIP()) + _netsio.setBaudrate(_sioBaud); + else + _serial.setBaudrate(_sioBaud); } // Set HSIO index. Sets high speed SIO baud and also returns that value. @@ -675,9 +681,9 @@ int systemBus::setHighSpeedIndex(int hsio_index) Debug_printf("Set HSIO baud from %d to %d (index %d), alt=%d\n", temp, _sioBaudHigh, hsio_index, alt); #else - if (hsio_index == HSIO_DISABLED_INDEX) + if (hsio_index == HSIO_INVALID_INDEX) { - _sioHighSpeedIndex = HSIO_DISABLED_INDEX; + _sioHighSpeedIndex = HSIO_INVALID_INDEX; _sioBaudHigh = SIO_STANDARD_BAUDRATE; // 19200 Debug_print("HSIO disabled\n"); return _sioBaudHigh; @@ -735,9 +741,9 @@ void systemBus::set_command_processed(bool processed) // Empty acknowledgment message for NetSIO hub void systemBus::sio_empty_ack() { - if (_port.get_sio_mode() == SioCom::sio_mode::NETSIO) + if (isBoIP()) { - _port.netsio_empty_sync(); + netsio_empty_sync(); } } #endif @@ -829,7 +835,7 @@ void systemBus::setUltraHigh(bool _enable, int _ultraHighBaud) ledc_channel_config(&ledc_channel_sio_ckin); ledc_timer_config(&ledc_timer); #endif - _port.set_baudrate(_sioBaudUltraHigh); + setBaudrate(_sioBaudUltraHigh); } else { @@ -839,16 +845,44 @@ void systemBus::setUltraHigh(bool _enable, int _ultraHighBaud) ledc_stop(LEDC_ESP32XX_HIGH_SPEED, LEDC_CHANNEL_1, 0); ledc_stop(LEDC_SPEED_MODE_MAX, LEDC_CHANNEL_1, 0); #endif - _port.set_baudrate(SIO_STANDARD_BAUDRATE); + setBaudrate(SIO_STANDARD_BAUDRATE); } } bool systemBus::motor_asserted() { + if (_port == &_netsio) + return _netsio.motorAsserted(); + #ifdef ESP_PLATFORM return (bool)fnSystem.digital_read(PIN_MTR); #else - return _port.motor_asserted(); + return false; #endif } + +bool systemBus::commandAsserted() +{ +#ifdef ESP_PLATFORM + return fnSystem.digital_read(_commandPin) == DIGI_LOW; +#else /* ! ESP_PLATFORM */ + if (_port == &_netsio) + return _netsio.commandAsserted(); + + RS232ChannelProtocol *rs232 = dynamic_cast(_port); + switch (_commandPin) + { + case fnConfig::SERIAL_COMMAND_DSR: + return rs232->getDTR(); + case fnConfig::SERIAL_COMMAND_CTS: + return rs232->getRTS(); + case fnConfig::SERIAL_COMMAND_RI: + return rs232->getRI(); + default: + break; + } + return false; +#endif /* ESP_PLATFORM */ +} + #endif /* BUILD_ATARI */ diff --git a/lib/bus/sio/sio.h b/lib/bus/sio/sio.h index aa66996a8..fa63f767c 100755 --- a/lib/bus/sio/sio.h +++ b/lib/bus/sio/sio.h @@ -1,23 +1,10 @@ #ifndef SIO_H #define SIO_H +#include "UARTChannel.h" +#include "NetSIO.h" #include -#ifdef ESP_PLATFORM -#include -#include -#else -#include "sio/siocom/fnSioCom.h" -#endif - -#ifdef ESP_PLATFORM -#include "fnUART.h" -#define MODEM_UART_T UARTManager -#else -// fnSioCom.h is included from bus.h -#define MODEM_UART_T SioCom -#endif - #define DELAY_T4 850 #define DELAY_T5 250 @@ -282,11 +269,10 @@ class systemBus bool useUltraHigh = false; // Use fujinet derived clock. -#ifdef ESP_PLATFORM - MODEM_UART_T _port = MODEM_UART_T(FN_UART_BUS); -#else - MODEM_UART_T _port; -#endif + IOChannel *_port = nullptr; + UARTChannel _serial; + NetSIO _netsio; + int _commandPin; #ifndef ESP_PLATFORM bool _command_processed = false; @@ -295,6 +281,8 @@ class systemBus void _sio_process_cmd(); void _sio_process_queue(); + void configureGPIO(); + public: void setup(); void service(); @@ -322,17 +310,13 @@ class systemBus bool shuttingDown = false; // TRUE if we are in shutdown process bool getShuttingDown() { return shuttingDown; }; -#ifndef ESP_PLATFORM - void set_command_processed(bool processed); - void sio_empty_ack(); // for NetSIO, notify hub we are not interested to handle the command -#endif - sioCassette *getCassette() { return _cassetteDev; } sioPrinter *getPrinter() { return _printerdev; } sioCPM *getCPM() { return _cpmDev; } // I wish this codebase would make up its mind to use camel or snake casing. modem *get_modem() { return _modemDev; } + bool commandAsserted(); #ifdef ESP_PLATFORM QueueHandle_t qSioMessages = nullptr; @@ -340,37 +324,55 @@ class systemBus // Everybody thinks "oh I know how a serial port works, I'll just // access it directly and bypass the bus!" ಠ_ಠ - size_t read(void *buffer, size_t length) { return _port.readBytes((uint8_t *) buffer, length); } - size_t read() { return _port.read(); } - size_t write(const void *buffer, size_t length) { return _port.write((uint8_t *) buffer, length); } - size_t write(int n) { return _port.write(n); } - size_t available() { return _port.available(); } - void flush() { _port.flush(); } - void discardInput() { _port.flush_input(); } - size_t print(int n, int base = 10) { return _port.print(n, base); } - size_t print(const char *str) { return _port.print(str); } - size_t print(const std::string &str) { return _port.print(str); } + size_t read(void *buffer, size_t length) { return _port->read(buffer, length); } + size_t read() { return _port->read(); } + size_t write(const void *buffer, size_t length) { return _port->write(buffer, length); } + size_t write(int n) { return _port->write(n); } + size_t available() { return _port->available(); } + void flushOutput() { _port->flushOutput(); } + void discardInput() { _port->discardInput(); } + size_t print(int n, int base = 10) { return _port->print(n, base); } + size_t print(const char *str) { return _port->print(str); } + size_t print(const std::string &str) { return _port->print(str); } #ifndef ESP_PLATFORM // specific to NetSioPort - void set_netsio_host(const char *host, int port) { _port.set_netsio_host(host, port); } - const char* get_netsio_host(int &port) { return _port.get_netsio_host(port); } - void netsio_late_sync(uint8_t c) { _port.netsio_late_sync(c); } - void netsio_empty_sync() { _port.netsio_empty_sync(); } - void netsio_write_size(int write_size) { _port.netsio_write_size(write_size); } +#ifdef UNUSED + void set_netsio_host(const char *host, int port) { _netsio.set_netsio_host(host, port); } + const char* get_netsio_host(int &port) { return _netsio.get_netsio_host(port); } +#endif /* UNUSED */ + void netsio_empty_sync() { _netsio.sendEmptySync(); } + void netsio_late_sync(uint8_t c) { _netsio.setSyncAckByte(c); } + void netsio_write_size(int write_size) { _netsio.setWriteSize(write_size); } + + void set_command_processed(bool processed); + void sio_empty_ack(); // for NetSIO, notify hub we are not interested to handle the command + +#ifdef UNUSED // get/set SIO mode - SioCom::sio_mode get_sio_mode() { return _port.get_sio_mode(); } - void set_sio_mode(SioCom::sio_mode mode) { _port.set_sio_mode(mode); } - void reset_sio_port(SioCom::sio_mode mode) { _port.reset_sio_port(mode); } - - void set_proceed(bool level) { _port.set_proceed(level); } - bool poll(int ms) { return _port.poll(ms); } - bool command_asserted() { return _port.command_asserted(); } - void bus_idle(uint16_t ms) { _port.bus_idle(ms); } + SioCom::sio_mode get_sio_mode() { return _netsio.get_sio_mode(); } + void set_sio_mode(SioCom::sio_mode mode) { _netsio.set_sio_mode(mode); } + void reset_sio_port(SioCom::sio_mode mode) { _netsio.reset_sio_port(mode); } + + bool poll(int ms) { return _netsio.poll(ms); } + bool command_asserted() { return _netsio.commandAsserted(); } +#endif /* UNUSED */ + void set_proceed(bool level) { _netsio.setProceed(level); } + void bus_idle(uint16_t ms) { _netsio.busIdle(ms); } #endif /* ESP_PLATFORM */ bool motor_asserted(); + + /* BoIP things */ + bool isBoIP() { return _port == &_netsio; } + void setHost(const char *host, int port) { _netsio.setHost(host, port); } + void selectSerialPort(bool useSerial) { + if (useSerial) + _port = &_serial; + else + _port = &_netsio; + } }; extern systemBus SYSTEM_BUS; diff --git a/lib/bus/sio/siocom/fnSioCom.cpp b/lib/bus/sio/siocom/fnSioCom.cpp deleted file mode 100644 index 4f165bbde..000000000 --- a/lib/bus/sio/siocom/fnSioCom.cpp +++ /dev/null @@ -1,258 +0,0 @@ -#ifndef ESP_PLATFORM - -#ifdef BUILD_ATARI - -#include "fnSioCom.h" - -#include "debug.h" -/* - * SIO Communication class - * (replacement for UARTManager fnUartSIO) - * It uses SioPort for data exchange and to control SIO lines - * SioPort can be physical serial port (SerialSioPort) to communicate with real Atari computer - * or network SIO (NetSio = SIO over UDP) for use with Altirra Atari Emulator - */ - -SioCom::SioCom() : _sio_mode(sio_mode::SERIAL), _sioPort(&_serialSio) {} - -void SioCom::begin(int baud) -{ - if (baud) - _sioPort->begin(baud); - else - _sioPort->begin(get_baudrate()); -} - -void SioCom::end() -{ - _sioPort->end(); -} - -/* - Poll the SIO port - * ms = milliseconds to wait for "port event" - * return true if port handling is needed - */ -bool SioCom::poll(int ms) -{ - return _sioPort->poll(ms); -} - -void SioCom::set_baudrate(uint32_t baud) -{ - _sioPort->set_baudrate(baud); -} - -uint32_t SioCom::get_baudrate() -{ - return _sioPort->get_baudrate(); -} - -bool SioCom::command_asserted() -{ - return _sioPort->command_asserted(); -} - -bool SioCom::motor_asserted() -{ - return _sioPort->motor_asserted(); -} - -void SioCom::set_proceed(bool level) -{ - _sioPort->set_proceed(level); -} - -void SioCom::set_interrupt(bool level) -{ - _sioPort->set_interrupt(level); -} - -int SioCom::available() -{ - return _sioPort->available(); -} - -void SioCom::flush() -{ - _sioPort->flush(); -} - -void SioCom::flush_input() -{ - _sioPort->flush_input(); -} - -// read single byte -int SioCom::read() -{ - return _sioPort->read(); -} - -// read bytes into buffer -size_t SioCom::read(uint8_t *buffer, size_t length) -{ - return _sioPort->read(buffer, length); -} - -// alias to read -size_t SioCom::readBytes(uint8_t *buffer, size_t length) -{ - return _sioPort->read(buffer, length); -} - -// write single byte -ssize_t SioCom::write(uint8_t b) -{ - return _sioPort->write(b); -} - -// write buffer -ssize_t SioCom::write(const uint8_t *buffer, size_t size) -{ - return _sioPort->write(buffer, size); -} - -// write C-string -ssize_t SioCom::write(const char *str) -{ - return _sioPort->write((const uint8_t *)str, strlen(str)); -}; - -// print utility functions - -size_t SioCom::_print_number(unsigned long n, uint8_t base) -{ - char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. - char *str = &buf[sizeof(buf) - 1]; - - *str = '\0'; - - // prevent crash if called with base == 1 - if(base < 2) - base = 10; - - do { - unsigned long m = n; - n /= base; - char c = m - base * n; - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while(n); - - return write(str); -} - -size_t SioCom::print(const char *str) -{ - return write(str); -} - -size_t SioCom::print(std::string str) -{ - return print(str.c_str()); -} - -size_t SioCom::print(int n, int base) -{ - return print((long) n, base); -} - -size_t SioCom::print(unsigned int n, int base) -{ - return print((unsigned long) n, base); -} - -size_t SioCom::print(long n, int base) -{ - if(base == 0) { - return write(n); - } else if(base == 10) { - if(n < 0) { - // int t = print('-'); - int t = print("-"); - n = -n; - return _print_number(n, 10) + t; - } - return _print_number(n, 10); - } else { - return _print_number(n, base); - } -} - -size_t SioCom::print(unsigned long n, int base) -{ - if(base == 0) { - return write(n); - } else { - return _print_number(n, base); - } -} - -void SioCom::bus_idle(uint16_t ms) -{ - _sioPort->bus_idle(ms); -} - -// specific to SerialSioPort -void SioCom::set_serial_port(const char *device, int command_pin, int proceed_pin) -{ - Debug_printf("SioCom::set_serial_port %s,%d,%d\n", device ? device : "NULL", command_pin, proceed_pin); - _serialSio.set_port(device, command_pin, proceed_pin); -}; - -const char* SioCom::get_serial_port(int &command_pin, int &proceed_pin) -{ - return _serialSio.get_port(command_pin, proceed_pin); -}; - -// specific to NetSioPort -void SioCom::set_netsio_host(const char *host, int port) -{ - _netSio.set_host(host, port); -} - -const char* SioCom::get_netsio_host(int &port) -{ - return _netSio.get_host(port); -} - -void SioCom::netsio_late_sync(uint8_t c) -{ - _netSio.set_sync_ack_byte(c); -} - -void SioCom::netsio_empty_sync() -{ - _netSio.send_empty_sync(); -} - -void SioCom::netsio_write_size(int write_size) -{ - _netSio.set_sync_write_size(write_size + 1); // data + checksum byte -} - -void SioCom::set_sio_mode(sio_mode mode) -{ - _sio_mode = mode; - switch(mode) - { - case sio_mode::NETSIO: - _sioPort = &_netSio; - break; - default: - _sioPort = &_serialSio; - } -} - -// toggle NetSIOPort and SerialPort -void SioCom::reset_sio_port(sio_mode mode) -{ - uint32_t baud = get_baudrate(); - end(); - set_sio_mode(mode); - begin(baud); -} - -#endif // BUILD_ATARI - -#endif // !ESP_PLATFORM diff --git a/lib/bus/sio/siocom/fnSioCom.h b/lib/bus/sio/siocom/fnSioCom.h deleted file mode 100644 index 5ba6849f0..000000000 --- a/lib/bus/sio/siocom/fnSioCom.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef SIOCOM_H -#define SIOCOM_H - -#include - -#include "sioport.h" -#include "netsio.h" -#include "serialsio.h" - -/* - * SIO Communication class - * (replacement for UARTManager fnUartSIO) - * It uses SioPort for data exchange and to control SIO lines - * SioPort can be physical serial port (SerialSioPort) to communicate with real Atari computer - * or network SIO (NetSio = SIO over UDP) for use with Altirra Atari Emulator - */ - -class SioCom -{ -public: - // supported SIO port types - enum sio_mode - { - SERIAL = 0, - NETSIO - }; - -private: - sio_mode _sio_mode; - SioPort *_sioPort; - SerialSioPort _serialSio; - NetSioPort _netSio; - - size_t _print_number(unsigned long n, uint8_t base); - -public: - SioCom(); - void begin(int baud = 0); - void end(); - bool poll(int ms); - - void set_baudrate(uint32_t baud); - uint32_t get_baudrate(); - - bool command_asserted(); - bool motor_asserted(); - void set_proceed(bool level); - void set_interrupt(bool level); - - int available(); - void flush(); - void flush_input(); - - // read single byte - int read(); - // read bytes into buffer - size_t read(uint8_t *buffer, size_t length); - // alias to read - size_t readBytes(uint8_t *buffer, size_t length); - - // write single byte - ssize_t write(uint8_t b); - // write buffer - ssize_t write(const uint8_t *buffer, size_t size); - // write C-string - ssize_t write(const char *str); - - // print utility functions - size_t print(const char *str); - size_t print(std::string str); - size_t print(int n, int base = 10); - size_t print(unsigned int n, int base = 10); - size_t print(long n, int base = 10); - size_t print(unsigned long n, int base = 10); - - void bus_idle(uint16_t ms); - - // specific to SerialSioPort - void set_serial_port(const char *device, int command_pin, int proceed_pin); - const char* get_serial_port(int &command_pin, int &proceed_pin); - - // specific to NetSioPort - void set_netsio_host(const char *host, int port); - const char* get_netsio_host(int &port); - void netsio_late_sync(uint8_t c); - void netsio_empty_sync(); - void netsio_write_size(int write_size); - - // get/set SIO mode - sio_mode get_sio_mode() {return _sio_mode;} - void set_sio_mode(sio_mode mode); - - void reset_sio_port(sio_mode mode); -}; - -#endif // SIOCOM_H diff --git a/lib/bus/sio/siocom/netsio.h b/lib/bus/sio/siocom/netsio.h deleted file mode 100644 index a67f12c37..000000000 --- a/lib/bus/sio/siocom/netsio.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef NETSIO_H -#define NETSIO_H - -#include -#include "sioport.h" -#include "fnDNS.h" - -class NetSioPort : public SioPort -{ -private: - char _host[64]; - in_addr_t _ip; - uint16_t _port; - - uint32_t _baud; - uint32_t _baud_peer; - int _fd; - bool _initialized; - bool _command_asserted; - bool _motor_asserted; - - uint8_t _rxbuf[1024]; - int _rxhead; - int _rxtail; - bool _rxfull; - - int _sync_request_num; // 0..255 sync request sequence number, -1 if sync is not requested - uint8_t _sync_ack_byte; // ACK byte to send with sync response - int _sync_write_size; // 0 .. no SIO write (from computer), > 0 .. expected bytes written - - // serial port error counter - int _errcount; - uint64_t _resume_time; - uint64_t _alive_time; // when last message was received - uint64_t _alive_request; // when last ALIVE request was sent - // flow control - int _credit; - -protected: - void suspend(int ms=5000); - bool resume_test(); - bool keep_alive(); - - int handle_netsio(); - static timeval timeval_from_ms(const uint32_t millis); - - bool wait_sock_readable(uint32_t timeout_ms); - bool wait_for_data(uint32_t timeout_ms); - bool wait_for_credit(int needed); - - bool wait_sock_writable(uint32_t timeout_ms); - ssize_t write_sock(const uint8_t *buffer, size_t size, uint32_t timeout_ms=500); - - bool rxbuffer_empty(); - bool rxbuffer_put(uint8_t b); - int rxbuffer_get(); - int rxbuffer_available(); - void rxbuffer_flush(); - -public: - NetSioPort(); - virtual ~NetSioPort(); - virtual void begin(int baud) override; - virtual void end() override; - virtual bool poll(int ms) override; - - virtual void set_baudrate(uint32_t baud) override; - virtual uint32_t get_baudrate() override; - - virtual bool command_asserted() override; - virtual bool motor_asserted() override; - virtual void set_proceed(bool level) override; - virtual void set_interrupt(bool level) override; - - virtual void bus_idle(uint16_t ms) override; - - virtual int available() override; - virtual void flush() override; - virtual void flush_input() override; - - // read single byte - virtual int read() override; - // read bytes into buffer - virtual size_t read(uint8_t *buffer, size_t length) override; - - // write single byte - virtual ssize_t write(uint8_t b) override; - // write buffer - virtual ssize_t write(const uint8_t *buffer, size_t size) override; - - // specific to NetSioPort - void set_host(const char *host, int port); - const char* get_host(int &port); - int ping(int count=4, int interval_ms=1000, int timeout_ms=500, bool fast=true); - - void set_sync_ack_byte(int ack_byte); - void set_sync_write_size(int write_size); - ssize_t send_sync_response(uint8_t response_type, uint8_t ack_byte=0, uint16_t sync_write_size=0); - void send_empty_sync(); -}; - -#endif // NETSIO_H diff --git a/lib/bus/sio/siocom/netsio_proto.h b/lib/bus/sio/siocom/netsio_proto.h deleted file mode 100644 index 4aafe50ac..000000000 --- a/lib/bus/sio/siocom/netsio_proto.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef NETSIO_PROTO_H -#define NETSIO_PROTO_H - -#define NETSIO_DATA_BYTE 0x01 -#define NETSIO_DATA_BLOCK 0x02 - -#define NETSIO_FILL_BUFFER 0x02 -#define NETSIO_TRANSMITT_BUFFER 0x03 - -#define NETSIO_DATA_BYTE_SYNC 0x09 - -#define NETSIO_COMMAND_OFF 0x10 -#define NETSIO_COMMAND_ON 0x11 -#define NETSIO_COMMAND_OFF_SYNC 0x18 -#define NETSIO_MOTOR_OFF 0x20 -#define NETSIO_MOTOR_ON 0x21 -#define NETSIO_PROCEED_OFF 0x30 -#define NETSIO_PROCEED_ON 0x31 -#define NETSIO_INTERRUPT_OFF 0x40 -#define NETSIO_INTERRUPT_ON 0x41 - -#define NETSIO_SPEED_CHANGE 0x80 -#define NETSIO_SYNC_RESPONSE 0x81 -#define NETSIO_BUS_IDLE 0x88 - -#define NETSIO_DEVICE_DISCONNECT 0xC0 -#define NETSIO_DEVICE_CONNECT 0xC1 -#define NETSIO_PING_REQUEST 0xC2 -#define NETSIO_PING_RESPONSE 0xC3 -#define NETSIO_ALIVE_REQUEST 0xC4 -#define NETSIO_ALIVE_RESPONSE 0xC5 -#define NETSIO_CREDIT_STATUS 0xC6 -#define NETSIO_CREDIT_UPDATE 0xC7 - -#define NETSIO_WARM_RESET 0xFE -#define NETSIO_COLD_RESET 0xFF - - -#define NETSIO_EMPTY_SYNC 0x00 -#define NETSIO_ACK_SYNC 0x01 - -#define NETSIO_PORT 9997 - -#endif // NETSIO_PROTO_H diff --git a/lib/bus/sio/siocom/serialsio.cpp b/lib/bus/sio/siocom/serialsio.cpp deleted file mode 100644 index a71d8cce3..000000000 --- a/lib/bus/sio/siocom/serialsio.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ESP_PLATFORM - -#ifdef BUILD_ATARI - -#include "serialsio.h" -#include "fnSystem.h" - -void SerialSioPort::bus_idle(uint16_t ms) -{ - fnSystem.delay(ms); -} - -#endif // BUILD_ATARI - -#endif // !ESP_PLATFORM \ No newline at end of file diff --git a/lib/bus/sio/siocom/serialsio.h b/lib/bus/sio/siocom/serialsio.h deleted file mode 100644 index e79ef9a6e..000000000 --- a/lib/bus/sio/siocom/serialsio.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef SERIALSIO_H -#define SERIALSIO_H - -#include - -#include "fnUART.h" -#include "sioport.h" - -/* - * Implementation of SIO Port using UART serial port - * wrapper around existing UARTManager - */ - -class SerialSioPort : public SioPort -{ -private: - UARTManager _uart; -public: - SerialSioPort() {} - virtual void begin(int baud) override { _uart.begin(baud); } - virtual void end() override { _uart.end(); } - virtual bool poll(int ms) override { return _uart.poll(ms); } - - virtual void set_baudrate(uint32_t baud) override { _uart.set_baudrate(baud); } - virtual uint32_t get_baudrate() override { return _uart.get_baudrate(); } - - virtual bool command_asserted() override { return _uart.command_asserted(); } - virtual bool motor_asserted() override { return _uart.motor_asserted(); } - virtual void set_proceed(bool level) override { _uart.set_proceed(level); } - virtual void set_interrupt(bool level) override { _uart.set_interrupt(level); } - - virtual void bus_idle(uint16_t ms) override; - - virtual int available() override { return _uart.available(); } - virtual void flush() override { _uart.flush(); } - virtual void flush_input() override { _uart.flush_input(); } - - // read single byte - virtual int read() override { return _uart.read(); } - // read bytes into buffer - virtual size_t read(uint8_t *buffer, size_t length) override { - return _uart.readBytes(buffer, length); - } - - // write single byte - virtual ssize_t write(uint8_t b) override { return _uart.write(b); } - // write buffer - virtual ssize_t write(const uint8_t *buffer, size_t size) override { - return _uart.write(buffer, size); - } - - // specific to SerialSioPort/UART - void set_port(const char *device, int command_pin, int proceed_pin) { - _uart.set_port(device, command_pin, proceed_pin); - } - const char* get_port(int &command_pin, int &proceed_pin) { - return _uart.get_port(&command_pin, &proceed_pin); - } -}; - -#endif // SERIALSIO_H diff --git a/lib/bus/sio/siocom/sioport.cpp b/lib/bus/sio/siocom/sioport.cpp deleted file mode 100644 index 7d69e6aa8..000000000 --- a/lib/bus/sio/siocom/sioport.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef ESP_PLATFORM - -#ifdef BUILD_ATARI - -#include "sioport.h" - -#endif // BUILD_ATARI - -#endif // !ESP_PLATFORM \ No newline at end of file diff --git a/lib/bus/sio/siocom/sioport.h b/lib/bus/sio/siocom/sioport.h deleted file mode 100644 index 5dd3cb227..000000000 --- a/lib/bus/sio/siocom/sioport.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef SIOPORT_H -#define SIOPORT_H - -#include -#include - -# define SIOPORT_DEFAULT_BAUD 19200 - -/* - * Abstraction of SIO port - * provides interface to basic functionality and signals - */ - -class SioPort -{ -public: - virtual void begin(int baud) = 0; - virtual void end() = 0; - virtual bool poll(int ms) = 0; - - virtual void set_baudrate(uint32_t baud) = 0; - virtual uint32_t get_baudrate() = 0; - - virtual bool command_asserted() = 0; - virtual bool motor_asserted() = 0; - virtual void set_proceed(bool level) = 0; - virtual void set_interrupt(bool level) = 0; - - virtual void bus_idle(uint16_t ms) = 0; - - virtual int available() = 0; - virtual void flush() = 0; - virtual void flush_input() = 0; - - virtual int read() = 0; // read single byte - virtual size_t read(uint8_t *buffer, size_t length) = 0; // read bytes into buffer - - virtual ssize_t write(uint8_t b) = 0; // write single byte - virtual ssize_t write(const uint8_t *buffer, size_t size) = 0; // write buffer -}; - -#endif // SIOPORT_H diff --git a/lib/config/fnConfig.h b/lib/config/fnConfig.h index 1cad2a9d9..d6a1f7ecb 100755 --- a/lib/config/fnConfig.h +++ b/lib/config/fnConfig.h @@ -18,17 +18,14 @@ #define HOST_SLOT_INVALID -1 -#ifdef ESP_PLATFORM # define HSIO_INVALID_INDEX -1 +#ifdef ESP_PLATFORM # define CONFIG_FILENAME "/fnconfig.ini" -// ESP_PLATFORM -#else -// !ESP_PLATFORM -# define HSIO_DISABLED_INDEX -1 // HSIO disabled, use standard speed only +#else /* ! ESP_PLATFORM */ # define CONFIG_FILENAME "fnconfig.ini" # define SD_CARD_DIR "SD" # define WEB_SERVER_LISTEN_URL "http://0.0.0.0:8000" -#endif +#endif /* ESP_PLATFORM */ // Bus Over IP default port #if defined(BUILD_ATARI) @@ -446,11 +443,7 @@ class fnConfig struct general_info { std::string devicename = "FujiNet"; -#ifdef ESP_PLATFORM int hsio_index = HSIO_INVALID_INDEX; -#else - int hsio_index = HSIO_DISABLED_INDEX; -#endif std::string timezone; bool rotation_sounds = true; bool config_enabled = true; diff --git a/lib/config/fnc_serial.cpp b/lib/config/fnc_serial.cpp index b71ffefa1..f48411151 100644 --- a/lib/config/fnc_serial.cpp +++ b/lib/config/fnc_serial.cpp @@ -1,7 +1,8 @@ #include "fnConfig.h" -#include #include "fnSystem.h" #include "utils.h" +#include +#include #include "../../include/debug.h" @@ -59,7 +60,7 @@ void fnConfig::_read_section_boip(std::stringstream &ss) else if (strcasecmp(name.c_str(), "port") == 0) { int port = atoi(value.c_str()); - if (port <= 0 || port > 65535) + if (port <= 0 || port > 65535) port = CONFIG_DEFAULT_BOIP_PORT; _boip.port = port; } @@ -147,7 +148,7 @@ void fnConfig::store_serial_proceed(serial_proceed_pin proceed_pin) void fnConfig::store_bos_enabled(bool bos_enabled) { if (_bos.bos_enabled == bos_enabled) return; - + _bos.bos_enabled = bos_enabled; _dirty = true; } @@ -155,7 +156,7 @@ void fnConfig::store_bos_enabled(bool bos_enabled) { void fnConfig::store_bos_port_name(char *port_name) { if (_bos.port_name.compare(port_name) == 0) return; - + _bos.port_name = port_name; _dirty = true; } @@ -163,7 +164,7 @@ void fnConfig::store_bos_port_name(char *port_name) { void fnConfig::store_bos_baud(int baud) { if (_bos.baud == baud) return; - + _bos.baud = baud; _dirty = true; } @@ -171,7 +172,7 @@ void fnConfig::store_bos_baud(int baud) { void fnConfig::store_bos_bits(int bits) { if (_bos.bits == bits) return; - + _bos.bits = bits; _dirty = true; } @@ -179,7 +180,7 @@ void fnConfig::store_bos_bits(int bits) { void fnConfig::store_bos_parity(int parity) { if (_bos.parity == parity) return; - + _bos.parity = parity; _dirty = true; } @@ -187,7 +188,7 @@ void fnConfig::store_bos_parity(int parity) { void fnConfig::store_bos_stop_bits(int stop_bits) { if (_bos.stop_bits == stop_bits) return; - + _bos.stop_bits = stop_bits; _dirty = true; } @@ -195,7 +196,7 @@ void fnConfig::store_bos_stop_bits(int stop_bits) { void fnConfig::store_bos_flowcontrol(int flowcontrol) { if (_bos.flowcontrol == flowcontrol) return; - + _bos.flowcontrol = flowcontrol; _dirty = true; } diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index 6ed3cf083..ffad1446c 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -349,7 +349,6 @@ void adamFuji::adamnet_copy_file() string copySpec; string sourcePath; string destPath; - uint8_t ck; FILE *sourceFile; FILE *destFile; char *dataBuf; @@ -364,7 +363,7 @@ void adamFuji::adamnet_copy_file() sourceSlot = adamnet_recv(); destSlot = adamnet_recv(); adamnet_recv_buffer(csBuf, sizeof(csBuf)); - ck = adamnet_recv(); + adamnet_recv(); SYSTEM_BUS.wait_for_idle(); SYSTEM_BUS.write(0x9f); // ACK. @@ -591,9 +590,6 @@ void adamFuji::image_rotate() count--; - // Save the device ID of the disk in the last slot - int last_id = count; - for (int n = 0; n < count; n++) { _fnDisks[n].access_mode = accessmode_save[n + 1]; diff --git a/lib/device/adamnet/modem.cpp b/lib/device/adamnet/modem.cpp index d49076795..87fe62318 100755 --- a/lib/device/adamnet/modem.cpp +++ b/lib/device/adamnet/modem.cpp @@ -7,7 +7,6 @@ #include "fnSystem.h" #include "fnConfig.h" -#include "fnUART.h" #include "fnWiFi.h" #include "utils.h" diff --git a/lib/device/drivewire/cassette.cpp b/lib/device/drivewire/cassette.cpp index 353d25ea3..399e6f975 100755 --- a/lib/device/drivewire/cassette.cpp +++ b/lib/device/drivewire/cassette.cpp @@ -13,7 +13,6 @@ #include "../../include/debug.h" #include "fnSystem.h" -#include "fnUART.h" #include "fnFsSD.h" #include "fnFsSPIFFS.h" @@ -84,4 +83,4 @@ void drivewireCassette::shutdown() { } -#endif /* BUILD_COCO */ \ No newline at end of file +#endif /* BUILD_COCO */ diff --git a/lib/device/drivewire/cpm.cpp b/lib/device/drivewire/cpm.cpp index a40605d53..5269efd88 100755 --- a/lib/device/drivewire/cpm.cpp +++ b/lib/device/drivewire/cpm.cpp @@ -7,7 +7,6 @@ #include "cpm.h" #include "fnSystem.h" -#include "fnUART.h" #include "fnWiFi.h" #include "fuji.h" #include "fnFS.h" @@ -66,13 +65,13 @@ drivewireCPM::drivewireCPM() void drivewireCPM::ready() { - fnDwCom.write(0x01); + SYSTEM_BUS.write(0x01); } void drivewireCPM::send_response() { // Send body - fnDwCom.write((uint8_t *)response.c_str(),response.length()); + SYSTEM_BUS.write((uint8_t *)response.c_str(),response.length()); // Clear the response response.clear(); @@ -94,8 +93,8 @@ void drivewireCPM::boot() void drivewireCPM::read() { - uint8_t lenh = fnDwCom.read(); - uint8_t lenl = fnDwCom.read(); + uint8_t lenh = SYSTEM_BUS.read(); + uint8_t lenl = SYSTEM_BUS.read(); uint16_t len = (lenh * 256) + lenl; uint16_t mw = uxQueueMessagesWaiting(rxq); @@ -121,8 +120,8 @@ void drivewireCPM::read() void drivewireCPM::write() { - uint8_t lenh = fnDwCom.read(); - uint8_t lenl = fnDwCom.read(); + uint8_t lenh = SYSTEM_BUS.read(); + uint8_t lenl = SYSTEM_BUS.read(); uint16_t len = (lenh * 256) + lenl; if (!len) @@ -130,7 +129,7 @@ void drivewireCPM::write() for (uint16_t i=0;i -#include "fnUART.h" #include "dload.h" #include "fnFsSPIFFS.h" #include "../../include/debug.h" @@ -54,9 +53,9 @@ void drivewireDload::pfilr_from_coco() { blockNum = 0; - if (fnDwCom.available()) + if (SYSTEM_BUS.available()) { - switch (fnDwCom.read()) + switch (SYSTEM_BUS.read()) { case P_FILR: Debug_printv("P.FILR"); @@ -73,7 +72,7 @@ void drivewireDload::pfilr_from_coco() void drivewireDload::pfilr_to_coco() { Debug_printv("Replying P_FILR"); - fnDwCom.write(P_FILR); + SYSTEM_BUS.write(P_FILR); dState = GET_FILENAME; } @@ -83,11 +82,11 @@ void drivewireDload::get_filename() memset(fn, 0x00, sizeof(fn)); - fnDwCom.readBytes((uint8_t *)fn, 8); + SYSTEM_BUS.read((uint8_t *)fn, 8); Debug_printv("Requested Filename %s", fn); - sum_from_host = fnDwCom.read(); + sum_from_host = SYSTEM_BUS.read(); if (xor_sum((uint8_t *)fn, 8) == sum_from_host) { @@ -102,14 +101,14 @@ void drivewireDload::get_filename() void drivewireDload::invalid_filename() { Debug_printv("Invalid Filename"); - fnDwCom.write(P_NAK); + SYSTEM_BUS.write(P_NAK); dState = PFILR_FROM_COCO; } void drivewireDload::valid_filename() { Debug_printv("Valid Filename"); - fnDwCom.write(P_ACK); + SYSTEM_BUS.write(P_ACK); dState = SEND_FILETYPE_TO_COCO; } @@ -151,9 +150,9 @@ void drivewireDload::send_filetype_file_not_found() { Debug_printv("Sending file not found response."); - fnDwCom.write(0xFF); // File type - fnDwCom.write(0x00); // ASCII flag - fnDwCom.write(0xFF); // XOR byte + SYSTEM_BUS.write(0xFF); // File type + SYSTEM_BUS.write(0x00); // ASCII flag + SYSTEM_BUS.write(0xFF); // XOR byte // Return to initial state. dState = PFILR_FROM_COCO; @@ -162,9 +161,9 @@ void drivewireDload::send_filetype_file_not_found() void drivewireDload::send_filetype_binary() { Debug_printv("Sending binary filetype"); - fnDwCom.write(0x02); // Binary file - fnDwCom.write(0x00); // ASCII flag = 0 - fnDwCom.write(0x02); // XOR value :) + SYSTEM_BUS.write(0x02); // Binary file + SYSTEM_BUS.write(0x00); // ASCII flag = 0 + SYSTEM_BUS.write(0x02); // XOR value :) dState = P_BLKR_FROM_COCO; } @@ -173,10 +172,10 @@ void drivewireDload::pblkr_from_coco() { uint8_t c = 0; - if (!fnDwCom.available()) + if (!SYSTEM_BUS.available()) return; - c = fnDwCom.read(); + c = SYSTEM_BUS.read(); if (c != P_BLKR) { @@ -188,7 +187,7 @@ void drivewireDload::pblkr_from_coco() void drivewireDload::pblkr_to_coco() { - fnDwCom.write(P_BLKR); + SYSTEM_BUS.write(P_BLKR); dState = GET_BLOCK_NUMBER; } @@ -198,11 +197,11 @@ void drivewireDload::get_block_number() uint8_t s = 0; // XOR sum // Read block bytes - b[0] = fnDwCom.read(); - b[1] = fnDwCom.read(); + b[0] = SYSTEM_BUS.read(); + b[1] = SYSTEM_BUS.read(); // Go ahead and get sum byte - s = fnDwCom.read(); + s = SYSTEM_BUS.read(); // quickly check bit MSB of each block byte and bail if set. if ((b[0] & 0x80) || (b[1] & 0x80)) @@ -233,14 +232,14 @@ void drivewireDload::get_block_number() void drivewireDload::get_p_nak() { Debug_printv("Sending NAK"); - fnDwCom.write(P_NAK); + SYSTEM_BUS.write(P_NAK); dState = P_BLKR_FROM_COCO; } void drivewireDload::get_p_ack() { Debug_printv("Sending ACK"); - fnDwCom.write(P_ACK); + SYSTEM_BUS.write(P_ACK); dState = PUT_BLOCK; } @@ -266,9 +265,9 @@ void drivewireDload::put_block() } // And spit out block length, block data and XOR sum. - fnDwCom.write(len); - fnDwCom.write(b, sizeof(b)); - fnDwCom.write(xor_sum(b, sizeof(b))); + SYSTEM_BUS.write(len); + SYSTEM_BUS.write(b, sizeof(b)); + SYSTEM_BUS.write(xor_sum(b, sizeof(b))); // Return to P.BLKR dState = P_BLKR_FROM_COCO; @@ -326,4 +325,4 @@ void drivewireDload::dload_process() } } -#endif /* BUILD_COCO */ \ No newline at end of file +#endif /* BUILD_COCO */ diff --git a/lib/device/drivewire/fuji.cpp b/lib/device/drivewire/fuji.cpp index 688efc4fb..90f2169d6 100644 --- a/lib/device/drivewire/fuji.cpp +++ b/lib/device/drivewire/fuji.cpp @@ -157,7 +157,7 @@ void drivewireFuji::net_scan_result() { Debug_println("Fuji cmd: GET SCAN RESULT"); - uint8_t n = fnDwCom.read(); + uint8_t n = SYSTEM_BUS.read(); wifiScanStarted = false; @@ -229,7 +229,7 @@ void drivewireFuji::net_set_ssid() char password[MAX_WIFI_PASS_LEN]; } cfg; - fnDwCom.readBytes((uint8_t *)&cfg, sizeof(cfg)); + SYSTEM_BUS.read((uint8_t *)&cfg, sizeof(cfg)); bool save = false; // for now don't save - to do save if connection was succesful @@ -287,7 +287,7 @@ void drivewireFuji::mount_host() { Debug_println("Fuji cmd: MOUNT HOST"); - unsigned char hostSlot = fnDwCom.read(); + unsigned char hostSlot = SYSTEM_BUS.read(); _fnHosts[hostSlot].mount(); } @@ -303,8 +303,8 @@ void drivewireFuji::disk_image_mount() Debug_println("Fuji cmd: MOUNT IMAGE"); - uint8_t deviceSlot = fnDwCom.read(); - uint8_t options = fnDwCom.read(); // DISK_ACCESS_MODE + uint8_t deviceSlot = SYSTEM_BUS.read(); + uint8_t options = SYSTEM_BUS.read(); // DISK_ACCESS_MODE errorCode = 1; @@ -548,7 +548,7 @@ void drivewireFuji::mount_all() // Set boot mode void drivewireFuji::set_boot_mode() { - insert_boot_device(fnDwCom.read()); + insert_boot_device(SYSTEM_BUS.read()); boot_config = true; } @@ -571,7 +571,7 @@ void drivewireFuji::open_app_key() { Debug_print("Fuji cmd: OPEN APPKEY\n"); - fnDwCom.readBytes((uint8_t *)&_current_appkey, sizeof(_current_appkey)); + SYSTEM_BUS.read((uint8_t *)&_current_appkey, sizeof(_current_appkey)); // Endian swap uint16_t tmp = _current_appkey.creator; @@ -616,14 +616,14 @@ void drivewireFuji::close_app_key() */ void drivewireFuji::write_app_key() { - uint8_t lenh = fnDwCom.read(); - uint8_t lenl = fnDwCom.read(); + uint8_t lenh = SYSTEM_BUS.read(); + uint8_t lenl = SYSTEM_BUS.read(); uint16_t len = lenh << 8 | lenl; uint8_t value[MAX_APPKEY_LEN]; memset(value,0,sizeof(value)); - fnDwCom.readBytes(value, len); + SYSTEM_BUS.read(value, len); // Make sure we have valid app key information if (_current_appkey.creator == 0 || _current_appkey.mode != APPKEYMODE_WRITE) @@ -724,7 +724,7 @@ void drivewireFuji::read_app_key() // Disk Image Unmount void drivewireFuji::disk_image_umount() { - uint8_t deviceSlot = fnDwCom.read(); + uint8_t deviceSlot = SYSTEM_BUS.read(); Debug_printf("Fuji cmd: UNMOUNT IMAGE 0x%02X\n", deviceSlot); @@ -797,9 +797,9 @@ void drivewireFuji::open_directory() errorCode = 1; - uint8_t hostSlot = fnDwCom.read(); + uint8_t hostSlot = SYSTEM_BUS.read(); - fnDwCom.readBytes((uint8_t *)&dirpath, 256); + SYSTEM_BUS.read((uint8_t *)&dirpath, 256); if (_current_open_directory_slot == -1) { @@ -877,8 +877,8 @@ char current_entry[256]; void drivewireFuji::read_directory_entry() { - uint8_t maxlen = fnDwCom.read(); - uint8_t addtl = fnDwCom.read(); + uint8_t maxlen = SYSTEM_BUS.read(); + uint8_t addtl = SYSTEM_BUS.read(); Debug_printf("Fuji cmd: READ DIRECTORY ENTRY (max=%hu) (addtl=%02x)\n", maxlen, addtl); @@ -937,8 +937,8 @@ void drivewireFuji::get_directory_position() uint16_t pos = _fnHosts[_current_open_directory_slot].dir_tell(); // Return the value we read - fnDwCom.write(pos << 8); - fnDwCom.write(pos & 0xFF); + SYSTEM_BUS.write(pos << 8); + SYSTEM_BUS.write(pos & 0xFF); errorCode = 1; } @@ -950,8 +950,8 @@ void drivewireFuji::set_directory_position() Debug_println("Fuji cmd: SET DIRECTORY POSITION"); // DAUX1 and DAUX2 hold the position to seek to in low/high order - h = fnDwCom.read(); - l = fnDwCom.read(); + h = SYSTEM_BUS.read(); + l = SYSTEM_BUS.read(); Debug_printf("H: %02x L: %02x", h, l); @@ -1061,7 +1061,7 @@ void drivewireFuji::new_disk() char filename[MAX_FILENAME_LEN]; // WIll set this to MAX_FILENAME_LEN, later. } newDisk; - fnDwCom.readBytes((uint8_t *)&newDisk, sizeof(newDisk)); + SYSTEM_BUS.read((uint8_t *)&newDisk, sizeof(newDisk)); Debug_printf("numDisks: %u\n",newDisk.numDisks); Debug_printf("hostSlot: %u\n",newDisk.hostSlot); @@ -1102,7 +1102,7 @@ void drivewireFuji::unmount_host() { Debug_println("Fuji cmd: UNMOUNT HOST"); - unsigned char hostSlot = fnDwCom.read(); + unsigned char hostSlot = SYSTEM_BUS.read(); // Unmount any disks associated with host slot for (int i = 0; i < MAX_DISK_DEVICES; i++) @@ -1143,7 +1143,7 @@ void drivewireFuji::write_host_slots() Debug_println("Fuji cmd: WRITE HOST SLOTS"); char hostSlots[MAX_HOSTS][MAX_HOSTNAME_LEN]; - fnDwCom.readBytes((uint8_t *)&hostSlots, sizeof(hostSlots)); + SYSTEM_BUS.read((uint8_t *)&hostSlots, sizeof(hostSlots)); for (int i = 0; i < MAX_HOSTS; i++) _fnHosts[i].set_hostname(hostSlots[i]); @@ -1214,7 +1214,7 @@ void drivewireFuji::write_device_slots() char filename[MAX_DISPLAY_FILENAME_LEN]; } diskSlots[MAX_DISK_DEVICES]; - fnDwCom.readBytes((uint8_t *)&diskSlots, sizeof(diskSlots)); + SYSTEM_BUS.read((uint8_t *)&diskSlots, sizeof(diskSlots)); // Load the data into our current device array for (int i = 0; i < MAX_DISK_DEVICES; i++) @@ -1291,12 +1291,12 @@ void drivewireFuji::set_device_filename() char tmp[MAX_FILENAME_LEN]; // AUX1 is the desired device slot - uint8_t slot = fnDwCom.read(); + uint8_t slot = SYSTEM_BUS.read(); // AUX2 contains the host slot and the mount mode (READ/WRITE) - uint8_t host = fnDwCom.read(); - uint8_t mode = fnDwCom.read(); + uint8_t host = SYSTEM_BUS.read(); + uint8_t mode = SYSTEM_BUS.read(); - fnDwCom.readBytes((uint8_t *)tmp, MAX_FILENAME_LEN); + SYSTEM_BUS.read((uint8_t *)tmp, MAX_FILENAME_LEN); Debug_printf("Fuji cmd: SET DEVICE SLOT 0x%02X/%02X/%02X FILENAME: %s\n", slot, host, mode, tmp); @@ -1323,7 +1323,7 @@ void drivewireFuji::get_device_filename() char tmp[MAX_FILENAME_LEN]; // AUX1 is the desired device slot - uint8_t slot = fnDwCom.read(); + uint8_t slot = SYSTEM_BUS.read(); if (slot > 7) { @@ -1391,8 +1391,8 @@ void drivewireFuji::insert_boot_device(uint8_t d) void drivewireFuji::base64_encode_input() { - uint8_t lenh = fnDwCom.read(); - uint8_t lenl = fnDwCom.read(); + uint8_t lenh = SYSTEM_BUS.read(); + uint8_t lenl = SYSTEM_BUS.read(); uint16_t len = lenh << 8 | lenl; if (!len) @@ -1403,7 +1403,7 @@ void drivewireFuji::base64_encode_input() } std::vector p(len); - fnDwCom.readBytes(p.data(), len); + SYSTEM_BUS.read(p.data(), len); base64.base64_buffer += std::string((const char *)p.data(), len); errorCode = 1; } @@ -1448,8 +1448,8 @@ void drivewireFuji::base64_encode_length() void drivewireFuji::base64_encode_output() { - uint8_t lenl = fnDwCom.read(); - uint8_t lenh = fnDwCom.read(); + uint8_t lenl = SYSTEM_BUS.read(); + uint8_t lenh = SYSTEM_BUS.read(); uint16_t len = lenh << 8 | lenl; if (!len) @@ -1470,8 +1470,8 @@ void drivewireFuji::base64_encode_output() void drivewireFuji::base64_decode_input() { - uint8_t lenl = fnDwCom.read(); - uint8_t lenh = fnDwCom.read(); + uint8_t lenl = SYSTEM_BUS.read(); + uint8_t lenh = SYSTEM_BUS.read(); uint16_t len = lenh << 8 | lenl; if (!len) @@ -1482,7 +1482,7 @@ void drivewireFuji::base64_decode_input() } std::vector p(len); - fnDwCom.readBytes(p.data(), len); + SYSTEM_BUS.read(p.data(), len); base64.base64_buffer += std::string((const char *)p.data(), len); errorCode = 1; @@ -1541,8 +1541,8 @@ void drivewireFuji::base64_decode_output() { Debug_printf("FUJI: BASE64 DECODE OUTPUT\n"); - uint8_t lenl = fnDwCom.read(); - uint8_t lenh = fnDwCom.read(); + uint8_t lenl = SYSTEM_BUS.read(); + uint8_t lenh = SYSTEM_BUS.read(); uint16_t len = lenh << 8 | lenl; if (!len) @@ -1576,8 +1576,8 @@ void drivewireFuji::base64_decode_output() void drivewireFuji::hash_input() { Debug_printf("FUJI: HASH INPUT\n"); - uint8_t lenl = fnDwCom.read(); - uint8_t lenh = fnDwCom.read(); + uint8_t lenl = SYSTEM_BUS.read(); + uint8_t lenh = SYSTEM_BUS.read(); uint16_t len = lenh << 8 | lenl; @@ -1589,7 +1589,7 @@ void drivewireFuji::hash_input() } std::vector p(len); - fnDwCom.readBytes(p.data(), len); + SYSTEM_BUS.read(p.data(), len); hasher.add_data(p); errorCode = 1; } @@ -1597,7 +1597,7 @@ void drivewireFuji::hash_input() void drivewireFuji::hash_compute(bool clear_data) { Debug_printf("FUJI: HASH COMPUTE\n"); - algorithm = Hash::to_algorithm(fnDwCom.read()); + algorithm = Hash::to_algorithm(SYSTEM_BUS.read()); hasher.compute(algorithm, clear_data); errorCode = 1; } @@ -1605,7 +1605,7 @@ void drivewireFuji::hash_compute(bool clear_data) void drivewireFuji::hash_length() { Debug_printf("FUJI: HASH LENGTH\n"); - uint8_t is_hex = fnDwCom.read() == 1; + uint8_t is_hex = SYSTEM_BUS.read() == 1; uint8_t r = hasher.hash_length(algorithm, is_hex); response = std::string((const char *)&r, 1); errorCode = 1; @@ -1615,7 +1615,7 @@ void drivewireFuji::hash_output() { Debug_printf("FUJI: HASH OUTPUT\n"); - uint8_t is_hex = fnDwCom.read() == 1; + uint8_t is_hex = SYSTEM_BUS.read() == 1; if (is_hex) { response = hasher.output_hex(); } else { @@ -1675,7 +1675,7 @@ fujiHost *drivewireFuji::set_slot_hostname(int host_slot, char *hostname) void drivewireFuji::send_error() { Debug_printf("drivewireFuji::send_error(%u)\n",errorCode); - fnDwCom.write(errorCode); + SYSTEM_BUS.write(errorCode); } void drivewireFuji::random() @@ -1693,7 +1693,7 @@ void drivewireFuji::random() void drivewireFuji::send_response() { // Send body - fnDwCom.write((uint8_t *)response.c_str(),response.length()); + SYSTEM_BUS.write((uint8_t *)response.c_str(),response.length()); // Clear the response response.clear(); @@ -1702,12 +1702,12 @@ void drivewireFuji::send_response() void drivewireFuji::ready() { - fnDwCom.write(0x01); // Yes, ready. + SYSTEM_BUS.write(0x01); // Yes, ready. } void drivewireFuji::process() { - uint8_t c = fnDwCom.read(); + uint8_t c = SYSTEM_BUS.read(); switch (c) { diff --git a/lib/device/drivewire/modem.cpp b/lib/device/drivewire/modem.cpp index c23a951f5..963f35d94 100644 --- a/lib/device/drivewire/modem.cpp +++ b/lib/device/drivewire/modem.cpp @@ -8,7 +8,6 @@ #include "fnSystem.h" #include "fnConfig.h" -#include "fnUART.h" #include "fnWiFi.h" #include "utils.h" @@ -467,7 +466,7 @@ void drivewireModem::at_handle_answer() CRX = true; cmdMode = false; - fnDwCom.flush(); + SYSTEM_BUS.flushOutput(); answerHack = false; } } @@ -968,252 +967,6 @@ void drivewireModem::modemCommand() cmd = ""; } -/* - Handle incoming & outgoing data for modem -*/ -// void drivewireModem::drivewire_handle_stream() -// { -// /**** AT command mode ****/ -// if (cmdMode == true) -// { -// if (answerHack == true) -// { -// Debug_printf("XXX ANSWERHACK !!! SENDING ATA! "); -// cmd = "ATA"; -// modemCommand(); -// answerHack = false; -// return; -// } - -// // In command mode but new unanswered incoming connection on server listen socket -// if ((listenPort > 0) && (tcpServer.hasClient())) -// { -// if (autoAnswer == true) -// { -// at_handle_answer(); -// } -// else -// { -// // Print RING every now and then while the new incoming connection exists -// if ((fnSystem.millis() - lastRingMs) > RING_INTERVAL) -// { -// if (numericResultCode == true) -// at_cmd_resultCode(RESULT_CODE_RING); -// else -// at_cmd_println("RING"); -// lastRingMs = fnSystem.millis(); -// } -// } -// } - -// // In command mode - don't exchange with TCP but gather characters to a string -// //if (SIO_UART.available() /*|| blockWritePending == true */ ) -// if (fnDwCom.available() > 0) -// { -// // get char from Atari SIO -// //char chr = SIO_UART.read(); -// char chr = fnDwCom.read(); - -// // Return, enter, new line, carriage return.. anything goes to end the command -// if ((chr == ASCII_LF) || (chr == ASCII_CR)) -// { -// modemCommand(); -// } -// // Backspace or delete deletes previous character -// else if ((chr == ASCII_BACKSPACE) || (chr == ASCII_DELETE)) -// { -// size_t len = cmd.length(); - -// if (len > 0) -// { -// cmd.erase(len - 1); -// // We don't assume that backspace is destructive -// // Clear with a space -// if (commandEcho == true) -// { -// // drivewire_send(ASCII_BACKSPACE); -// // drivewire_send(' '); -// // drivewire_send(ASCII_BACKSPACE); -// } -// } -// } -// // Take into account arrow key movement and clear screen -// else if (chr == ATASCII_CLEAR_SCREEN || -// ((chr >= ATASCII_CURSOR_UP) && (chr <= ATASCII_CURSOR_RIGHT))) -// { -// // if (commandEcho == true) -// // drivewire_send(chr); -// } -// else -// { -// if (cmd.length() < MAX_CMD_LENGTH) -// { -// //cmd.concat(chr); -// cmd += chr; -// } -// // if (commandEcho == true) -// // drivewire_send(chr); -// } -// } -// } -// // Connected mode -// else -// { -// // If another client is waiting, accept and turn away. -// if (tcpServer.hasClient()) -// { -// fnTcpClient c = tcpServer.accept(); -// c.write("The MODEM is currently serving another caller. Please try again later.\x0d\x0a\x9b"); -// c.stop(); -// } - -// // Emit a CONNECT if we're connected, and a few seconds have passed. -// if ((answered == false) && (answerTimer > 0) && ((fnSystem.millis() - answerTimer) > ANSWER_TIMER_MS)) -// { -// answered = true; -// answerTimer = 0; -// if (numericResultCode == true) -// { -// at_cmd_resultCode(modemBaud); -// } -// else -// { -// at_cmd_println("CONNECT ", false); -// at_cmd_println(modemBaud); -// } -// } - -// // //int sioBytesAvail = SIO_UART.available(); -// // int sioBytesAvail = drivewire_recv_available(); - -// // // send from Atari to Fujinet -// // if (sioBytesAvail && tcpClient.connected()) -// // { -// // // In telnet in worst case we have to escape every uint8_t -// // // so leave half of the buffer always free -// // //int max_buf_size; -// // //if (telnet == true) -// // // max_buf_size = TX_BUF_SIZE / 2; -// // //else -// // // max_buf_size = TX_BUF_SIZE; - -// // // Read from serial, the amount available up to -// // // maximum size of the buffer -// // // int sioBytesRead = drivewire_recv_buffer(&txBuf[0], //SIO_UART.readBytes(&txBuf[0], -// // // (sioBytesAvail > TX_BUF_SIZE) ? TX_BUF_SIZE : sioBytesAvail); - -// // // Disconnect if going to AT mode with "+++" sequence -// // // for (int i = 0; i < (int)sioBytesRead; i++) -// // // { -// // // if (txBuf[i] == '+') -// // // plusCount++; -// // // else -// // // plusCount = 0; -// // // if (plusCount >= 3) -// // // { -// // // plusTime = fnSystem.millis(); -// // // } -// // // if (txBuf[i] != '+') -// // // { -// // // plusCount = 0; -// // // } -// // // } - -// // // Write the buffer to TCP finally -// // if (use_telnet == true) -// // { -// // // telnet_send(telnet, (const char *)txBuf, sioBytesRead); -// // } -// // // else -// // // tcpClient.write(&txBuf[0], sioBytesRead); - -// // // And send it off to the sniffer, if enabled. -// // // modemSniffer->dumpOutput(&txBuf[0], sioBytesRead); -// // // _lasttime = fnSystem.millis(); -// // } - -// // read from Fujinet to Atari -// unsigned char buf[RECVBUFSIZE]; -// int bytesAvail = 0; - -// // check to see how many bytes are avail to read -// while ((bytesAvail = tcpClient.available()) > 0) -// { -// // read as many as our buffer size will take (RECVBUFSIZE) -// unsigned int bytesRead = -// tcpClient.read(buf, (bytesAvail > RECVBUFSIZE) ? RECVBUFSIZE : bytesAvail); - -// if (use_telnet == true) -// { -// telnet_recv(telnet, (const char *)buf, bytesRead); -// } -// else -// { -// // drivewire_send_buffer(buf, bytesRead); -// // drivewire_flush(); -// } - -// // And dump to sniffer, if enabled. -// modemSniffer->dumpInput(buf, bytesRead); -// _lasttime = fnSystem.millis(); -// } -// } - -// // If we have received "+++" as last bytes from serial port and there -// // has been over a second without any more bytes, go back to command mode. -// if (plusCount >= 3) -// { -// if (fnSystem.millis() - plusTime > 1000) -// { -// Debug_println("Going back to command mode"); - -// at_cmd_println("OK"); - -// cmdMode = true; - -// plusCount = 0; -// } -// } - -// // Go to command mode if TCP disconnected and not in command mode -// if (!tcpClient.connected() && (cmdMode == false) && (DTR == 0)) -// { -// tcpClient.flush(); -// tcpClient.stop(); -// cmdMode = true; -// if (numericResultCode == true) -// at_cmd_resultCode(RESULT_CODE_NO_CARRIER); -// else -// at_cmd_println("NO CARRIER"); -// telnet_free(telnet); -// telnet = telnet_init(telopts, _telnet_event_handler, 0, this); -// CRX = false; -// if (listenPort > 0) -// { -// // tcpServer.stop(); -// // tcpServer.begin(listenPort); -// } -// } -// else if ((!tcpClient.connected()) && (cmdMode == false)) -// { -// cmdMode = true; -// telnet_free(telnet); -// telnet = telnet_init(telopts, _telnet_event_handler, 0, this); -// if (numericResultCode == true) -// at_cmd_resultCode(RESULT_CODE_NO_CARRIER); -// else -// at_cmd_println("NO CARRIER"); -// telnet_free(telnet); -// telnet = telnet_init(telopts, _telnet_event_handler, 0, this); -// CRX = false; -// if (listenPort > 0) -// { -// // tcpServer.stop(); -// // tcpServer.begin(listenPort); -// } -// } -// } - void drivewireModem::shutdown() { if (modemSniffer != nullptr) diff --git a/lib/device/drivewire/modem.h b/lib/device/drivewire/modem.h index 9042725e4..f310c6aa7 100644 --- a/lib/device/drivewire/modem.h +++ b/lib/device/drivewire/modem.h @@ -12,7 +12,6 @@ #include "fnTcpClient.h" #include "modem-sniffer.h" #include "libtelnet.h" -#include "fnUART.h" /* Keep strings under 40 characters, for the benefit of 40-column users! */ #define HELPL01 " FujiNet Virtual RC2014 Modem" @@ -207,8 +206,6 @@ class drivewireModem : public virtualDevice void at_handle_pb(); void at_handle_pbclear(); - UARTManager* uart; // UART manager to use. - protected: void shutdown(); @@ -219,9 +216,6 @@ class drivewireModem : public virtualDevice drivewireModem(FileSystem *_fs, bool snifferEnable); virtual ~drivewireModem(); - void set_uart(UARTManager *_uart) { uart = _uart; } - - time_t get_last_activity_time() { return _lasttime; } // timestamp of last input or output. ModemSniffer *get_modem_sniffer() { return modemSniffer; } fnTcpClient get_tcp_client() { return tcpClient; } // Return TCP client. diff --git a/lib/device/drivewire/network.cpp b/lib/device/drivewire/network.cpp index a5411dd14..5b546c40b 100755 --- a/lib/device/drivewire/network.cpp +++ b/lib/device/drivewire/network.cpp @@ -129,7 +129,7 @@ void drivewireNetwork::timer_stop() void drivewireNetwork::ready() { - fnDwCom.write(0x01); // yes, ready. + SYSTEM_BUS.write(0x01); // yes, ready. } /** @@ -143,7 +143,7 @@ void drivewireNetwork::open() char tmp[256]; - size_t bytes_read = fnDwCom.readBytes((uint8_t *)tmp, 256); + size_t bytes_read = SYSTEM_BUS.read((uint8_t *)tmp, 256); tmp[sizeof(tmp)-1] = '\0'; Debug_printf("tmp = %s\n",tmp); @@ -195,7 +195,7 @@ void drivewireNetwork::open() delete protocolParser; protocolParser = nullptr; } - //fnDwCom.write(ns.error); + //SYSTEM_BUS.write(ns.error); return; } @@ -214,7 +214,7 @@ void drivewireNetwork::open() delete protocolParser; protocolParser = nullptr; } - //fnDwCom.write(ns.error); + //SYSTEM_BUS.write(ns.error); return; } @@ -232,7 +232,7 @@ void drivewireNetwork::open() // And signal complete! ns.error = 1; - //fnDwCom.write(ns.error); + //SYSTEM_BUS.write(ns.error); Debug_printf("ns.error = %u\n",ns.error); } @@ -255,7 +255,7 @@ void drivewireNetwork::close() // If no protocol enabled, we just signal complete, and return. if (protocol == nullptr) { - //fnDwCom.write(ns.error); + //SYSTEM_BUS.write(ns.error); return; } @@ -279,7 +279,7 @@ void drivewireNetwork::close() Debug_printv("After protocol delete %lu\n",esp_get_free_internal_heap_size()); #endif - //fnDwCom.write(ns.error); + //SYSTEM_BUS.write(ns.error); } /** @@ -393,7 +393,7 @@ void drivewireNetwork::write() return; } - if (fnDwCom.readBytes((uint8_t *)txbuf, num_bytes) < num_bytes) + if (SYSTEM_BUS.read((uint8_t *)txbuf, num_bytes) < num_bytes) { Debug_printf("drivewireNetwork::write() - short read\n"); free(txbuf); @@ -577,7 +577,7 @@ void drivewireNetwork::set_prefix() std::string prefixSpec_str; char tmp[256]; memset(tmp,0,sizeof(tmp)); - size_t read_bytes = fnDwCom.readBytes((uint8_t *)tmp, 256); + size_t read_bytes = SYSTEM_BUS.read((uint8_t *)tmp, 256); if (read_bytes != 256) { @@ -674,7 +674,7 @@ void drivewireNetwork::set_login() char tmp[256]; memset(tmp,0,sizeof(tmp)); - size_t bytes_read = fnDwCom.readBytes((uint8_t *)tmp, 256); + size_t bytes_read = SYSTEM_BUS.read((uint8_t *)tmp, 256); if (bytes_read != 256) { @@ -695,7 +695,7 @@ void drivewireNetwork::set_password() char tmp[256]; memset(tmp,0,sizeof(tmp)); - size_t bytes_read = fnDwCom.readBytes((uint8_t *)tmp, 256); + size_t bytes_read = SYSTEM_BUS.read((uint8_t *)tmp, 256); if (bytes_read != 256) { @@ -747,7 +747,7 @@ void drivewireNetwork::special_inquiry() do_inquiry(cmdFrame.aux1); // Finally, return the completed inq_dstats value back to CoCo - fnDwCom.write(&inq_dstats, sizeof(inq_dstats)); + SYSTEM_BUS.write(&inq_dstats, sizeof(inq_dstats)); } void drivewireNetwork::do_inquiry(unsigned char inq_cmd) @@ -896,7 +896,7 @@ void drivewireNetwork::special_80() // Get special (devicespec) from computer - fnDwCom.readBytes(spData,256); + SYSTEM_BUS.read(spData,256); Debug_printf("drivewireNetwork::special_80() - %s\n", spData); @@ -1047,7 +1047,7 @@ else void drivewireNetwork::send_error() { Debug_printf("drivewireNetwork::send_error(%u)\n",ns.error); - fnDwCom.write(ns.error); + SYSTEM_BUS.write(ns.error); } void drivewireNetwork::send_response() @@ -1059,7 +1059,7 @@ void drivewireNetwork::send_response() response.insert(response.length(), len - response.length(), '\0'); // Send body - fnDwCom.write((uint8_t *)response.c_str(), len); + SYSTEM_BUS.write((uint8_t *)response.c_str(), len); Debug_printf("drivewireNetwork::send_response[%d]:%s\n", len, response.c_str()); @@ -1234,7 +1234,7 @@ void drivewireNetwork::json_query() char tmpq[256]; memset(tmpq,0,sizeof(tmpq)); - size_t bytes_read = fnDwCom.readBytes((uint8_t *)tmpq,256); + size_t bytes_read = SYSTEM_BUS.read((uint8_t *)tmpq,256); // why does it need to be 256 bytes? if (bytes_read != 256) @@ -1302,9 +1302,9 @@ void drivewireNetwork::do_idempotent_command_80() void drivewireNetwork::process() { // Read the three command and aux bytes - cmdFrame.comnd = (uint8_t)fnDwCom.read(); - cmdFrame.aux1 = (uint8_t)fnDwCom.read(); - cmdFrame.aux2 = (uint8_t)fnDwCom.read(); + cmdFrame.comnd = (uint8_t)SYSTEM_BUS.read(); + cmdFrame.aux1 = (uint8_t)SYSTEM_BUS.read(); + cmdFrame.aux2 = (uint8_t)SYSTEM_BUS.read(); Debug_printf("comnd: '%c' %u,%u,%u\n",cmdFrame.comnd,cmdFrame.comnd,cmdFrame.aux1,cmdFrame.aux2); diff --git a/lib/device/iwm/cpm.cpp b/lib/device/iwm/cpm.cpp index 440377af1..f71fb9509 100644 --- a/lib/device/iwm/cpm.cpp +++ b/lib/device/iwm/cpm.cpp @@ -4,7 +4,6 @@ #include "cpm.h" #include "fnSystem.h" -#include "fnUART.h" #include "fnWiFi.h" #include "fuji.h" #include "fnFS.h" diff --git a/lib/device/iwm/modem.cpp b/lib/device/iwm/modem.cpp index 284181a4d..9f9efd1e2 100644 --- a/lib/device/iwm/modem.cpp +++ b/lib/device/iwm/modem.cpp @@ -5,7 +5,6 @@ #include "compat_inet.h" #include "../../include/atascii.h" #include "modem.h" -#include "../hardware/fnUART.h" #include "fnWiFi.h" #include "fnSystem.h" #include "../utils/utils.h" diff --git a/lib/device/rs232/fuji.cpp b/lib/device/rs232/fuji.cpp index e94c45cbf..878d4dc60 100755 --- a/lib/device/rs232/fuji.cpp +++ b/lib/device/rs232/fuji.cpp @@ -2,8 +2,6 @@ #include "fuji.h" -#include - #include #include @@ -17,6 +15,7 @@ #include "led.h" #include "utils.h" #include "string_utils.h" +#include "compat_string.h" rs232Fuji theFuji; // global fuji device object diff --git a/lib/device/rs232/modem.cpp b/lib/device/rs232/modem.cpp index 759b200ac..c945c98ea 100755 --- a/lib/device/rs232/modem.cpp +++ b/lib/device/rs232/modem.cpp @@ -696,7 +696,7 @@ void rs232Modem::at_cmd_println() SYSTEM_BUS.write(ASCII_CR); SYSTEM_BUS.write(ASCII_LF); } - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); } void rs232Modem::at_cmd_println(const char *s, bool addEol) @@ -717,7 +717,7 @@ void rs232Modem::at_cmd_println(const char *s, bool addEol) SYSTEM_BUS.write(ASCII_LF); } } - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); } void rs232Modem::at_cmd_println(int i, bool addEol) @@ -738,7 +738,7 @@ void rs232Modem::at_cmd_println(int i, bool addEol) SYSTEM_BUS.write(ASCII_LF); } } - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); } void rs232Modem::at_cmd_println(std::string s, bool addEol) @@ -759,7 +759,7 @@ void rs232Modem::at_cmd_println(std::string s, bool addEol) SYSTEM_BUS.write(ASCII_LF); } } - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); } void rs232Modem::at_handle_wificonnect() @@ -1025,7 +1025,7 @@ void rs232Modem::at_handle_answer() CRX = true; cmdMode = false; - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); answerHack = false; } } @@ -1678,8 +1678,8 @@ void rs232Modem::rs232_handle_modem() // Read from serial, the amount available up to // maximum size of the buffer - int rs232BytesRead = SYSTEM_BUS.read(&txBuf[0], //RS232_UART.readBytes(&txBuf[0], - (rs232BytesAvail > TX_BUF_SIZE) ? TX_BUF_SIZE : rs232BytesAvail); + int rs232BytesRead = SYSTEM_BUS.read(&txBuf[0], (rs232BytesAvail > TX_BUF_SIZE) + ? TX_BUF_SIZE : rs232BytesAvail); // Disconnect if going to AT mode with "+++" sequence for (int i = 0; i < (int)rs232BytesRead; i++) @@ -1729,7 +1729,7 @@ void rs232Modem::rs232_handle_modem() else { SYSTEM_BUS.write(buf, bytesRead); - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); } // And dump to sniffer, if enabled. diff --git a/lib/device/rs232/rs232cpm.cpp b/lib/device/rs232/rs232cpm.cpp index 1844b3442..3aca956b6 100755 --- a/lib/device/rs232/rs232cpm.cpp +++ b/lib/device/rs232/rs232cpm.cpp @@ -5,7 +5,6 @@ #include "rs232cpm.h" #include "fnSystem.h" -#include "fnUART.h" #include "fnWiFi.h" #include "fuji.h" #include "fnFS.h" @@ -58,6 +57,7 @@ void rs232CPM::rs232_handle_cpm() void rs232CPM::init_cpm(int baud) { +#warning "Why is CP/M mucking with the bus?" SYSTEM_BUS.setBaudrate(baud); Status = Debug = 0; Break = Step = -1; diff --git a/lib/device/sio/cassette.cpp b/lib/device/sio/cassette.cpp index f2e3bbcc5..e79f62400 100755 --- a/lib/device/sio/cassette.cpp +++ b/lib/device/sio/cassette.cpp @@ -7,7 +7,6 @@ #include "../../include/debug.h" #include "fnSystem.h" -#include "fnUART.h" #include "fnFsSD.h" #include "led.h" @@ -143,7 +142,7 @@ void sioCassette::open_cassette_file(FileSystem *_FS) strcpy(fn, CASSETTE_FILE); if (cassetteMode == cassette_mode_t::record) { - sprintf(mm, "%020llu", (unsigned long long)fnSystem.millis()); + snprintf(mm, sizeof(mm), "%020llu", (unsigned long long)fnSystem.millis()); strcat(fn, mm); } strcat(fn, ".cas"); @@ -384,7 +383,7 @@ size_t sioCassette::send_tape_block(size_t offset) SYSTEM_BUS.write(atari_sector_buffer, BLOCK_LEN + 3); //USART_Transmit_Byte(get_checksum(atari_sector_buffer, BLOCK_LEN + 3)); SYSTEM_BUS.write(sio_checksum(atari_sector_buffer, BLOCK_LEN + 3)); - SYSTEM_BUS.flush(); // wait for all data to be sent just like a tape + SYSTEM_BUS.flushOutput(); // wait for all data to be sent just like a tape // _delay_ms(300); //PRG(0-N) + PRWT(0.25s) delay fnSystem.delay(300); return (offset); @@ -479,7 +478,7 @@ size_t sioCassette::send_FUJI_tape_block(size_t offset) #else int step; // SYSTEM_BUS is fnSioCom - if (SYSTEM_BUS.get_sio_mode() == SioCom::sio_mode::NETSIO) + if (SYSTEM_BUS.isBoIP()) step = gap > 1000 ? 1000 : gap; // step is 1000 ms (NetSIO) else step = gap > 20 ? 20 : gap; // step is 20 ms (SerialSIO) @@ -524,7 +523,7 @@ size_t sioCassette::send_FUJI_tape_block(size_t offset) for (int i = 0; i < buflen; i++) Debug_printf("%02x ", atari_sector_buffer[i]); SYSTEM_BUS.write(atari_sector_buffer, buflen); - SYSTEM_BUS.flush(); // wait for all data to be sent just like a tape + SYSTEM_BUS.flushOutput(); // wait for all data to be sent just like a tape Debug_printf("\r\n"); if (first && atari_sector_buffer[2] == 0xfe) diff --git a/lib/device/sio/fuji.cpp b/lib/device/sio/fuji.cpp index e2d33870f..0e71e521d 100644 --- a/lib/device/sio/fuji.cpp +++ b/lib/device/sio/fuji.cpp @@ -360,7 +360,7 @@ void sioFuji::sio_set_baudrate() // send complete with current baudrate sio_complete(); - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); #ifndef ESP_PLATFORM fnSystem.delay_microseconds(2000); #endif @@ -648,13 +648,6 @@ void sioFuji::sio_copy_file() bool err = false; do { -#ifndef ESP_PLATFORM - if (SYSTEM_BUS.get_sio_mode() == SioCom::sio_mode::NETSIO && fnSystem.millis() - poll_ts > 1000) - { - SYSTEM_BUS.poll(1); - poll_ts = fnSystem.millis(); - } -#endif readCount = fnio::fread(dataBuf, 1, 532, sourceFile); readTotal += readCount; // Check if we got enough bytes on the read @@ -1513,8 +1506,8 @@ void sioFuji::sio_get_adapter_config_extended() strlcpy(cfg.sDnsIP, fnSystem.Net.get_ip4_dns_str().c_str(), 16); strlcpy(cfg.sNetmask, fnSystem.Net.get_ip4_mask_str().c_str(), 16); - sprintf(cfg.sMacAddress, "%02X:%02X:%02X:%02X:%02X:%02X", cfg.macAddress[0], cfg.macAddress[1], cfg.macAddress[2], cfg.macAddress[3], cfg.macAddress[4], cfg.macAddress[5]); - sprintf(cfg.sBssid, "%02X:%02X:%02X:%02X:%02X:%02X", cfg.bssid[0], cfg.bssid[1], cfg.bssid[2], cfg.bssid[3], cfg.bssid[4], cfg.bssid[5]); + snprintf(cfg.sMacAddress, sizeof(cfg.sMacAddress), "%02X:%02X:%02X:%02X:%02X:%02X", cfg.macAddress[0], cfg.macAddress[1], cfg.macAddress[2], cfg.macAddress[3], cfg.macAddress[4], cfg.macAddress[5]); + snprintf(cfg.sBssid, sizeof(cfg.sBssid), "%02X:%02X:%02X:%02X:%02X:%02X", cfg.bssid[0], cfg.bssid[1], cfg.bssid[2], cfg.bssid[3], cfg.bssid[4], cfg.bssid[5]); bus_to_computer((uint8_t *)&cfg, sizeof(cfg), false); diff --git a/lib/device/sio/modem.cpp b/lib/device/sio/modem.cpp index c4ece2949..5e4b33c7a 100755 --- a/lib/device/sio/modem.cpp +++ b/lib/device/sio/modem.cpp @@ -714,7 +714,7 @@ void modem::at_cmd_println() SYSTEM_BUS.write(ASCII_CR); SYSTEM_BUS.write(ASCII_LF); } - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); fnLedManager.set(LED_BT,false); } @@ -739,7 +739,7 @@ void modem::at_cmd_println(const char *s, bool addEol) SYSTEM_BUS.write(ASCII_LF); } } - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); fnLedManager.set(LED_BT,false); } @@ -764,7 +764,7 @@ void modem::at_cmd_println(int i, bool addEol) SYSTEM_BUS.write(ASCII_LF); } } - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); fnLedManager.set(LED_BT,false); } @@ -789,7 +789,7 @@ void modem::at_cmd_println(std::string s, bool addEol) SYSTEM_BUS.write(ASCII_LF); } } - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); fnLedManager.set(LED_BT,false); } @@ -1066,7 +1066,7 @@ void modem::at_handle_answer() CRX = true; cmdMode = false; - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); answerHack = false; } } @@ -1809,7 +1809,7 @@ void modem::sio_handle_modem() else { SYSTEM_BUS.write(buf, bytesRead); - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); } fnLedManager.set(eLed::LED_BT,false); diff --git a/lib/device/sio/pclink.cpp b/lib/device/sio/pclink.cpp index 303016bf2..c0399dff4 100644 --- a/lib/device/sio/pclink.cpp +++ b/lib/device/sio/pclink.cpp @@ -453,7 +453,7 @@ check_dos_name(char *newpath, struct dirent *dp, struct stat *sb) return 1; /* stat() the file (fetches the length) */ - sprintf(temp_fspec, "%s/%s", newpath, fname); + snprintf(temp_fspec, sizeof(temp_fspec), "%s/%s", newpath, fname); if (log_flag) Debug_printf("%s: stat '%s'\n", __func__, temp_fspec); @@ -2497,7 +2497,7 @@ pclink_read(uint8_t *buf, int len) Debug_printf("<-SIO read (PCLINK) %hu bytes\n", len); #ifndef ESP_PLATFORM - if (SYSTEM_BUS.get_sio_mode() == SioCom::sio_mode::NETSIO) + if (SYSTEM_BUS.isBoIP()) { SYSTEM_BUS.netsio_write_size(len); // set hint for NetSIO } @@ -2542,7 +2542,7 @@ pclink_write(uint8_t *buf, int len) // Write checksum SYSTEM_BUS.write(sio_checksum(buf, len)); - SYSTEM_BUS.flush(); + SYSTEM_BUS.flushOutput(); } diff --git a/lib/device/sio/udpstream.cpp b/lib/device/sio/udpstream.cpp index 12e6f28c6..c50dc1d22 100755 --- a/lib/device/sio/udpstream.cpp +++ b/lib/device/sio/udpstream.cpp @@ -128,7 +128,7 @@ void sioUDPStream::sio_handle_udpstream() #ifdef ESP_PLATFORM if (fnSystem.digital_read(PIN_CMD) == DIGI_LOW) #else - if (SYSTEM_BUS.command_asserted()) + if (SYSTEM_BUS.commandAsserted()) #endif { Debug_println("CMD Asserted in LOOP, stopping UDPStream"); diff --git a/lib/device/sio/udpstream.h b/lib/device/sio/udpstream.h index 2e78a3ff0..42dcbac85 100755 --- a/lib/device/sio/udpstream.h +++ b/lib/device/sio/udpstream.h @@ -34,7 +34,7 @@ class sioUDPStream : public virtualDevice uint8_t buf_net[UDPSTREAM_BUFFER_SIZE]; uint8_t buf_stream[UDPSTREAM_BUFFER_SIZE]; - uint8_t buf_stream_index=0; + unsigned int buf_stream_index=0; uint16_t packet_seq = 0; #ifdef ESP_PLATFORM diff --git a/lib/hardware/ACMChannel.cpp b/lib/hardware/ACMChannel.cpp new file mode 100644 index 000000000..6c48594ad --- /dev/null +++ b/lib/hardware/ACMChannel.cpp @@ -0,0 +1,234 @@ +#include "ACMChannel.h" + +#ifdef CONFIG_USB_CDC_ACM_HOST_ENABLED + +#include + +#include "../../include/debug.h" + +#define USB_HOST_PRIORITY (20) +// FIXME - don't hard code, use whatever CDC-ADM device is connected +#define USB_DEVICE_VID (0xf022) +#define USB_DEVICE_PID (0x4001) + +#define TX_STRING ("CDC test string!") +#define TX_TIMEOUT_MS (1000) + +#include // debug +#include + +#define DEBUG_TAG "SerialACM" + +#define MAX_FIFO_PAYLOAD 32 +typedef struct { + size_t length; + uint8_t data[MAX_FIFO_PAYLOAD]; +} FIFOPacket; + +static void usb_lib_task(void *arg) +{ + while (1) { + // Start handling system events + uint32_t event_flags; + usb_host_lib_handle_events(portMAX_DELAY, &event_flags); + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { + ESP_ERROR_CHECK(usb_host_device_free_all()); + } + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { + Debug_printv("USB: All devices freed"); + // Continue handling USB events to allow device reconnection + } + } +} + +static bool rxForwarder(const uint8_t *data, size_t length, void *arg) +{ + SerialACM *instance = (SerialACM *) arg; + + instance->dataReceived(data, length); + return true; +} + +void SerialACM::dataReceived(const uint8_t *data, size_t length) +{ + size_t offset; + FIFOPacket pkt; + BaseType_t woken; + + + Debug_printv("received %i", length); + for (offset = 0; length; offset += pkt.length, length -= pkt.length) + { + pkt.length = std::min(length, (size_t) MAX_FIFO_PAYLOAD); + memcpy(pkt.data, data + offset, pkt.length); + xQueueSendFromISR(rxQueue, &pkt, &woken); + } + + return; +} + +static void eventForwarder(const cdc_acm_host_dev_event_data_t *event, void *user_ctx) +{ + SerialACM *instance = (SerialACM *) user_ctx; + instance->eventReceived(event); + return; +} + +void SerialACM::eventReceived(const cdc_acm_host_dev_event_data_t *event) +{ + switch (event->type) { + case CDC_ACM_HOST_ERROR: + ESP_LOGE(DEBUG_TAG, "CDC-ACM error has occurred, err_no = %i", event->data.error); + break; + case CDC_ACM_HOST_DEVICE_DISCONNECTED: + Debug_printv("Device suddenly disconnected"); + ESP_ERROR_CHECK(cdc_acm_host_close(event->data.cdc_hdl)); + xSemaphoreGive(device_disconnected_sem); + break; + case CDC_ACM_HOST_SERIAL_STATE: + Debug_printv("Serial state notif 0x%04X", event->data.serial_state.val); + break; + case CDC_ACM_HOST_NETWORK_CONNECTION: + default: + ESP_LOGW(DEBUG_TAG, "Unsupported CDC event: %i", event->type); + break; + } +} + +void SerialACM::begin() +{ + rxQueue = xQueueCreate(1024 / MAX_FIFO_PAYLOAD, sizeof(FIFOPacket)); + + device_disconnected_sem = xSemaphoreCreateBinary(); + assert(device_disconnected_sem); + + // Install USB Host driver. Should only be called once in entire application + Debug_printv("Installing USB Host"); + usb_host_config_t host_config = {}; + host_config.skip_phy_setup = false; + host_config.intr_flags = ESP_INTR_FLAG_LEVEL1; + ESP_ERROR_CHECK(usb_host_install(&host_config)); + + // Create a task that will handle USB library events + BaseType_t task_created = xTaskCreate(usb_lib_task, "usb_lib", 4096, + xTaskGetCurrentTaskHandle(), + USB_HOST_PRIORITY, NULL); + assert(task_created == pdTRUE); + + Debug_printv("Installing CDC-ACM driver"); + ESP_ERROR_CHECK(cdc_acm_host_install(NULL)); + + cdc_acm_host_device_config_t dev_config = {}; + dev_config.connection_timeout_ms = 1000; + dev_config.out_buffer_size = 512; + dev_config.in_buffer_size = 512; + dev_config.user_arg = this; + dev_config.event_cb = eventForwarder; + dev_config.data_cb = rxForwarder; + + while (true) { + // Open USB device from tusb_serial_device example + // example. Either single or dual port configuration. + Debug_printv("Opening CDC ACM device 0x%04X:0x%04X...", USB_DEVICE_VID, + USB_DEVICE_PID); + esp_err_t err = cdc_acm_host_open(USB_DEVICE_VID, USB_DEVICE_PID, + 0, &dev_config, &cdc_dev); + if (ESP_OK != err) { +#if 0 + Debug_printv("Opening CDC ACM device 0x%04X:0x%04X...", + USB_DEVICE_VID, USB_DEVICE_DUAL_PID); + err = cdc_acm_host_open(USB_DEVICE_VID, USB_DEVICE_DUAL_PID, + 0, &dev_config, &cdc_dev); +#endif + if (ESP_OK != err) { + Debug_printv("Failed to open device"); + continue; + } + } + //cdc_acm_host_desc_print(cdc_dev); + vTaskDelay(pdMS_TO_TICKS(100)); + +#if 1 + // Test sending and receiving: responses are handled in handle_rx callback + ESP_ERROR_CHECK(cdc_acm_host_data_tx_blocking(cdc_dev, + (const uint8_t *) TX_STRING, + strlen(TX_STRING), + TX_TIMEOUT_MS)); +#endif + vTaskDelay(pdMS_TO_TICKS(100)); + + // Test Line Coding commands: Get current line coding, change + // it 9600 7N1 and read again + Debug_printv("Setting up line coding"); + + cdc_acm_line_coding_t line_coding; + ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding)); + Debug_printv("Line Get: Rate: %" PRIu32", Stop bits: %" PRIu8 + ", Parity: %" PRIu8", Databits: %" PRIu8"", + line_coding.dwDTERate, + line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits); + + line_coding.dwDTERate = 9600; + line_coding.bDataBits = 7; + line_coding.bParityType = 1; + line_coding.bCharFormat = 1; + ESP_ERROR_CHECK(cdc_acm_host_line_coding_set(cdc_dev, &line_coding)); + Debug_printv("Line Set: Rate: %" PRIu32", Stop bits: %" PRIu8 + ", Parity: %" PRIu8", Databits: %" PRIu8"", + line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, + line_coding.bDataBits); + + ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding)); + Debug_printv("Line Get: Rate: %" PRIu32", Stop bits: %" PRIu8 + ", Parity: %" PRIu8", Databits: %" PRIu8"", + line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, + line_coding.bDataBits); + + ESP_ERROR_CHECK(cdc_acm_host_set_control_line_state(cdc_dev, true, false)); + + // We are done. Wait for device disconnection and start over + Debug_printv( + "Example finished successfully! You can reconnect the device to run again."); + //xSemaphoreTake(device_disconnected_sem, portMAX_DELAY); + break; + } + + return; +} + +void SerialACM::end() +{ +} + +void SerialACM::update_fifo() +{ + FIFOPacket pkt; + size_t old_len; + + while (xQueueReceive(rxQueue, &pkt, 0)) + { + Debug_printv("packet %i", pkt.length); + old_len = fifo.size(); + fifo.resize(old_len + pkt.length); + memcpy(&fifo[old_len], pkt.data, pkt.length); + Debug_printv("fifo %i", fifo.size()); + } + + return; +} + +size_t SerialACM::si_send(const void *buffer, size_t length) +{ + cdc_acm_host_data_tx_blocking(cdc_dev, + (const uint8_t *) buffer, + length, + TX_TIMEOUT_MS); + return length; +} + +void SerialACM::flush() +{ + return; +} + +#endif /* CONFIG_USB_CDC_ACM_HOST_ENABLED */ diff --git a/lib/hardware/ACMChannel.h b/lib/hardware/ACMChannel.h new file mode 100644 index 000000000..93a5bfd0b --- /dev/null +++ b/lib/hardware/ACMChannel.h @@ -0,0 +1,39 @@ +#ifndef ACMCHANNEL_H +#define ACMCHANNEL_H + +#ifdef CONFIG_USB_CDC_ACM_HOST_ENABLED + +#include "IOChannel.h" + +#include +#include +#include + +class ACMChannel : public IOChannel, public RS232ChannelProtocol +{ +private: + SemaphoreHandle_t device_disconnected_sem; + cdc_acm_dev_hdl_t cdc_dev = NULL; + QueueHandle_t rxQueue; + +protected: + void update_fifo() override; + size_t si_send(const void *buffer, size_t length) override; + +public: + void begin(); + void end() override; + + void flushOutput() override; + + uint32_t getBaudrate() override { return 0; } + void setBaudrate(uint32_t baud) override { return } + + // public because forwarder function needs it + void eventReceived(const cdc_acm_host_dev_event_data_t *event); + void dataReceived(const uint8_t *data, size_t length); +}; + +#endif /* CONFIG_USB_CDC_ACM_HOST_ENABLED */ + +#endif /* ACMCHANNEL_H */ diff --git a/lib/hardware/COMChannel.cpp b/lib/hardware/COMChannel.cpp new file mode 100644 index 000000000..9b7d657ff --- /dev/null +++ b/lib/hardware/COMChannel.cpp @@ -0,0 +1,285 @@ +#include "COMChannel.h" + +#ifdef HELLO_IM_A_PC + +#include "../../include/debug.h" + +void COMChannel::begin(const ChannelConfig& conf) +{ + if (_fd != INVALID_HANDLE_VALUE) + end(); + + _device = conf.device; + read_timeout_ms = conf.read_timeout_ms; + discard_timeout_ms = conf.discard_timeout_ms; + + // Open the serial port + if (_device.empty()) + { + Debug_println("Serial port is not configured!"); + return; + } + + Debug_printf("Setting up serial port %s\n", _device.c_str()); + _fd = CreateFile(_device.c_str(), + GENERIC_READ | GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + + if (_fd == INVALID_HANDLE_VALUE) + { + DWORD err = GetLastError(); + Debug_printf("Failed to open serial port, error: %d\n", err); + if (err == ERROR_FILE_NOT_FOUND) + { + Debug_printf("Device not found\n"); + } + return; + } + + DCB dcbSerialParams = {0}; + dcbSerialParams.DCBlength=sizeof(dcbSerialParams); + + if (!GetCommState(_fd, &dcbSerialParams)) + { + //error getting state + Debug_printf("GetCommState error: %d\n", GetLastError()); + return; + } + + dcbSerialParams.ByteSize = 8; // 8 bits per byte + dcbSerialParams.StopBits = ONESTOPBIT; // one stop bit + dcbSerialParams.Parity = NOPARITY; // no parity + // no flowcontrol + dcbSerialParams.fOutxCtsFlow = false; + dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; + dcbSerialParams.fOutX = false; + dcbSerialParams.fInX = false; + + // activate settings + if (!SetCommState(_fd, &dcbSerialParams)){ + Debug_printf("SetCommState error: %d\n", GetLastError()); + return; + } + + Debug_printf("### UART initialized ###\n"); + setBaudrate(conf.baud_rate); + + return; +} + +void COMChannel::end() +{ + if (_fd != INVALID_HANDLE_VALUE) + { + CloseHandle(_fd); + _fd = INVALID_HANDLE_VALUE; + Debug_printf("### UART stopped ###\n"); + } + return; +} + +void COMChannel::updateFIFO() +{ + COMSTAT cs; + + if (_fd == INVALID_HANDLE_VALUE) + return; + + if (!ClearCommError(_fd, NULL, &cs)) + return; + if (!cs.cbInQue) + return; + + size_t old_len = _fifo.size(); + DWORD rxbytes; + _fifo.resize(old_len + cs.cbInQue); + if (!ReadFile(_fd, &_fifo[old_len], cs.cbInQue, &rxbytes, NULL)) + rxbytes = 0; + _fifo.resize(old_len + rxbytes); + + return; +} + +size_t COMChannel::dataOut(const void *buffer, size_t length) +{ + DWORD txbytes; + if (!WriteFile(_fd, buffer, (DWORD) length, &txbytes, NULL)) + { + Debug_printf("UART write() write error: %dn", GetLastError()); + } + return (size_t)txbytes; +} + +void COMChannel::flushOutput() +{ + if (_fd != INVALID_HANDLE_VALUE) + FlushFileBuffers(_fd); + return; +} + +void COMChannel::setBaudrate(uint32_t newBaud) +{ + Debug_printf("UART set_baudrate: %d\n", newBaud); + + if (_fd == INVALID_HANDLE_VALUE || newBaud == _baud) + return; + + _baud = newBaud; + + if (_baud == 0) + _baud = 19200; + + int baud_id = 0; + + // map baud rate to predefined constant + switch (_baud) + { +#ifdef CBR_300 + case 300: + baud_id = CBR_300; + break; +#endif +#ifdef CBR_600 + case 600: + baud_id = CBR_600; + break; +#endif +#ifdef CBR_1200 + case 1200: + baud_id = CBR_1200; + break; +#endif +#ifdef CBR_1800 + case 1800: + baud_id = CBR_1800; + break; +#endif +#ifdef CBR_2400 + case 2400: + baud_id = CBR_2400; + break; +#endif +#ifdef CBR_4800 + case 4800: + baud_id = CBR_4800; + break; +#endif +#ifdef CBR_9600 + case 9600: + baud_id = CBR_9600; + break; +#endif +#ifdef CBR_19200 + case 19200: + baud_id = CBR_19200; + break; +#endif +#ifdef CBR_38400 + case 38400: + baud_id = CBR_38400; + break; +#endif +#ifdef CBR_57600 + case 57600: + baud_id = CBR_57600; + break; +#endif +#ifdef CBR_115200 + case 115200: + baud_id = CBR_115200; + break; +#endif + default: + // no constant for given baud rate, try to blindly assign it + baud_id = _baud; + } + + DCB dcbSerialParams = {0}; + dcbSerialParams.DCBlength=sizeof(dcbSerialParams); + + if (!GetCommState(_fd, &dcbSerialParams)) + { + //error getting state + Debug_printf("GetCommState error: %d\n", GetLastError()); + return; + } + + dcbSerialParams.BaudRate = baud_id; + + // activate settings + if (!SetCommState(_fd, &dcbSerialParams)){ + Debug_printf("SetCommState error: %d\n", GetLastError()); + return; + } + + // Setup timeouts + COMMTIMEOUTS timeouts = {0}; + timeouts.ReadIntervalTimeout = 50; + timeouts.ReadTotalTimeoutConstant = 500; + timeouts.ReadTotalTimeoutMultiplier = 50; + timeouts.WriteTotalTimeoutConstant = 500; + timeouts.WriteTotalTimeoutMultiplier = 50; + if (!SetCommTimeouts(_fd, &timeouts)) + { + Debug_printf("Error setting timeouts.\n"); + } + + return; +} + +bool COMChannel::getDTR() +{ + DWORD status; + + if (!GetCommModemStatus(_fd, &status)) + return false; + return !!(status & MS_DSR_ON); +} + +void COMChannel::setDSR(bool state) +{ + int status; + + if (state == _dtrState) + return; + + _dtrState = state; + EscapeCommFunction(_fd, _dtrState ? SETDTR : CLRDTR); + return; +} + +bool COMChannel::getRTS() +{ + DWORD status; + + if (!GetCommModemStatus(_fd, &status)) + return false; + return !!(status & MS_CTS_ON); +} + +void COMChannel::setCTS(bool state) +{ + int status; + + if (state == _dtrState) + return; + + _dtrState = state; + EscapeCommFunction(_fd, _dtrState ? SETRTS : CLRRTS); + return; +} + +bool COMChannel::getRI() +{ + DWORD status; + + if (!GetCommModemStatus(_fd, &status)) + return false; + return !!(status & MS_RING_ON); +} + +#endif /* HELLO_IM_A_PC */ diff --git a/lib/hardware/COMChannel.h b/lib/hardware/COMChannel.h new file mode 100644 index 000000000..38a2b18d5 --- /dev/null +++ b/lib/hardware/COMChannel.h @@ -0,0 +1,70 @@ +#ifndef COMCHANNEL_H +#define COMCHANNEL_H + +#include "IOChannel.h" +#include "RS232ChannelProtocol.h" + +#ifdef HELLO_IM_A_PC + +#include +#include + +struct ChannelConfig +{ + std::string device; + int baud_rate; + uint32_t read_timeout_ms = IOCHANNEL_DEFAULT_TIMEOUT; + uint32_t discard_timeout_ms = IOCHANNEL_DEFAULT_TIMEOUT; + + ChannelConfig& baud(int baud) { + baud_rate = baud; return *this; + } + ChannelConfig& deviceID(std::string path) { + device = path; return *this; + } + ChannelConfig& readTimeout(uint32_t millis) { + read_timeout_ms = millis; return *this; + } + ChannelConfig& discardTimeout(uint32_t millis) { + discard_timeout_ms = millis; return *this; + } +}; + +class COMChannel : public IOChannel, public RS232ChannelProtocol +{ +private: + HANDLE _fd = INVALID_HANDLE_VALUE; + std::string _device; + uint32_t _baud; + bool _dtrState = true, _rtsState = true; + +protected: + void updateFIFO() override; + size_t dataOut(const void *buffer, size_t length) override; + +public: + void begin(const ChannelConfig& conf); + void end() override; + + void flushOutput() override; + + uint32_t getBaudrate() override { return _baud; } + void setBaudrate(uint32_t baud) override; + + // FujiNet acts as modem (DCE), computer serial ports are DTE. + // API names follow the modem (DCE) view, but the actual RS-232 pin differs. + bool getDTR() override; // modem DTR input → actually reads RS-232 DSR pin + void setDSR(bool state) override; // modem DSR output → actually drives RS-232 DTR pin + bool getRTS() override; // modem RTS input → actually reads RS-232 CTS pin + void setCTS(bool state) override; // modem CTS output → actually drives RS-232 RTS pin + bool getRI() override; // Ring Indicator is only an input on DTE :-/ + +#ifdef UNUSED + void setPort(std::string device); + std::string getPort(); +#endif /* UNUSED */ +}; + +#endif /* HELLO_IM_A_PC */ + +#endif /* COMCHANNEL_H */ diff --git a/lib/hardware/ESP32UARTChannel.cpp b/lib/hardware/ESP32UARTChannel.cpp new file mode 100644 index 000000000..af8a7e729 --- /dev/null +++ b/lib/hardware/ESP32UARTChannel.cpp @@ -0,0 +1,152 @@ +#include "ESP32UARTChannel.h" +#include "fnSystem.h" +#include "../../include/pinmap.h" +#include "../../include/debug.h" + +#include +#include + +#define MAX_FLUSH_WAIT_TICKS 200 + +// Serial "debug port" +ESP32UARTChannel fnDebugConsole; + +void ESP32UARTChannel::begin(const ChannelConfig& conf) +{ + if (_uart_q) + { + end(); + } + + _uart_num = conf.device; + read_timeout_ms = conf.read_timeout_ms; + discard_timeout_ms = conf.discard_timeout_ms; + Debug_printv("speed: %i", conf.uart_config.baud_rate); + uart_param_config(_uart_num, &conf.uart_config); + + int tx, rx; + if (_uart_num == 0) + { + rx = PIN_UART0_RX; + tx = PIN_UART0_TX; + } + else if (_uart_num == 1) + { + rx = PIN_UART1_RX; + tx = PIN_UART1_TX; + } + else if (_uart_num == 2) + { + rx = PIN_UART2_RX; + tx = PIN_UART2_TX; + } + else + { + return; + } + + uart_set_pin(_uart_num, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + + if (conf.isInverted) + uart_set_line_inverse(_uart_num, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV); + + // Arduino default buffer size is 256 + int uart_buffer_size = UART_HW_FIFO_LEN(uart_num) * 2; + int uart_queue_size = 10; + int intr_alloc_flags = 0; + + // Install UART driver using an event queue here + uart_driver_install(_uart_num, uart_buffer_size, 0, uart_queue_size, &_uart_q, + intr_alloc_flags); +} + +void ESP32UARTChannel::end() +{ + uart_driver_delete(_uart_num); + if (_uart_q) + vQueueDelete(_uart_q); + _uart_q = NULL; +} + +void ESP32UARTChannel::updateFIFO() +{ + uart_event_t event; + + while (xQueueReceive(_uart_q, &event, 1)) + { + if (event.type == UART_DATA) + { + size_t old_len = _fifo.size(); + _fifo.resize(old_len + event.size); + int result = uart_read_bytes(_uart_num, &_fifo[old_len], event.size, 0); + if (result < 0) + result = 0; + _fifo.resize(old_len + result); + } + } + + return; +} + +void ESP32UARTChannel::flushOutput() +{ + uart_wait_tx_done(_uart_num, MAX_FLUSH_WAIT_TICKS); +} + +uint32_t ESP32UARTChannel::getBaudrate() +{ + uint32_t baud; + uart_get_baudrate(_uart_num, &baud); + return baud; +} + +void ESP32UARTChannel::setBaudrate(uint32_t baud) +{ +#ifdef DEBUG + uint32_t before; + uart_get_baudrate(_uart_num, &before); +#endif + uart_set_baudrate(_uart_num, baud); +#ifdef DEBUG + Debug_printf("set_baudrate change from %d to %d\r\n", before, baud); +#endif +} + +size_t ESP32UARTChannel::dataOut(const void *buffer, size_t size) +{ + return uart_write_bytes(_uart_num, (const char *)buffer, size); +} + +bool ESP32UARTChannel::getDTR() +{ +#if defined(FUJINET_OVER_USB) || !defined(PIN_RS232_DTR) + return 0; +#else /* FUJINET_OVER_USB */ + return fnSystem.digital_read(PIN_RS232_DTR) == DIGI_LOW; +#endif /* FUJINET_OVER_USB */ +} + +void ESP32UARTChannel::setDSR(bool state) +{ +#if !defined(FUJINET_OVER_USB) && defined(PIN_RS232_DSR) + fnSystem.digital_write(PIN_RS232_DSR, !state); +#endif + return; +} + +bool ESP32UARTChannel::getRTS() +{ +#if defined(FUJINET_OVER_USB) || !defined(PIN_RS232_RTS) + return 0; +#else /* FUJINET_OVER_USB */ + return fnSystem.digital_read(PIN_RS232_RTS) == DIGI_LOW; +#endif /* FUJINET_OVER_USB */ +} + +void ESP32UARTChannel::setCTS(bool state) +{ +#if !defined(FUJINET_OVER_USB) && defined(PIN_RS232_CTS) + fnSystem.digital_write(PIN_RS232_CTS, !state); +#endif + return; +} diff --git a/lib/hardware/ESP32UARTChannel.h b/lib/hardware/ESP32UARTChannel.h new file mode 100644 index 000000000..b64ea539b --- /dev/null +++ b/lib/hardware/ESP32UARTChannel.h @@ -0,0 +1,100 @@ +#ifndef ESP32UARTCHANNEL_H +#define ESP32UARTCHANNEL_H + +#include "IOChannel.h" +#include "RS232ChannelProtocol.h" + +#ifdef ESP_PLATFORM + +#include +#include + +#define FN_UART_DEBUG UART_NUM_0 +#if defined(BUILD_RS232) || defined(PINMAP_COCO_ESP32S3) || defined(PINMAP_COCO_RS232) +# define FN_UART_BUS UART_NUM_1 +#else +# define FN_UART_BUS UART_NUM_2 +#endif + +struct ChannelConfig +{ + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 122, + .source_clk = UART_SCLK_DEFAULT, + .flags = { + .allow_pd = 0, + .backup_before_sleep = 0, + } + }; + bool isInverted = false; + uart_port_t device; + uint32_t read_timeout_ms = IOCHANNEL_DEFAULT_TIMEOUT; + uint32_t discard_timeout_ms = IOCHANNEL_DEFAULT_TIMEOUT; + + ChannelConfig& baud(int baud) { + uart_config.baud_rate = baud; return *this; + } + ChannelConfig& dataBits(uart_word_length_t bits) { + uart_config.data_bits = bits; return *this; + } + ChannelConfig& parity(uart_parity_t par) { + uart_config.parity = par; return *this; + } + ChannelConfig& stopBits(uart_stop_bits_t bits) { + uart_config.stop_bits = bits; return *this; + } + ChannelConfig& flowControl(uart_hw_flowcontrol_t flow) { + uart_config.flow_ctrl = flow; return *this; + } + ChannelConfig& inverted(bool inv) { + isInverted = inv; return *this; + } + ChannelConfig& deviceID(uart_port_t num) { + device = num; return *this; + } + ChannelConfig& readTimeout(uint32_t millis) { + read_timeout_ms = millis; return *this; + } + ChannelConfig& discardTimeout(uint32_t millis) { + discard_timeout_ms = millis; return *this; + } +}; + +class ESP32UARTChannel : public IOChannel, public RS232ChannelProtocol +{ +private: + uart_port_t _uart_num; + QueueHandle_t _uart_q; + +protected: + void updateFIFO() override; + size_t dataOut(const void *buffer, size_t length) override; + +public: + void begin(const ChannelConfig& conf); + void end() override; + + void flushOutput() override; + + uint32_t getBaudrate() override; + void setBaudrate(uint32_t baud) override; + + // FujiNet acts as modem (DCE), computer serial ports are DTE. + // API names follow the modem (DCE) view, but the actual RS-232 pin differs. + bool getDTR() override; // modem DTR input → actually reads RS-232 DSR pin + void setDSR(bool state) override; // modem DSR output → actually drives RS-232 DTR pin + bool getRTS() override; // modem RTS input → actually reads RS-232 CTS pin + void setCTS(bool state) override; // modem CTS output → actually drives RS-232 RTS pin + bool getRI() override { return 0; }; // Ring Indicator is only an input on DTE +}; + +extern ESP32UARTChannel fnDebugConsole; + +#endif /* ESP_PLATFORM */ + +#endif /* ESP32UARTCHANNEL_H */ diff --git a/lib/hardware/IOChannel.cpp b/lib/hardware/IOChannel.cpp new file mode 100644 index 000000000..9d92e9d85 --- /dev/null +++ b/lib/hardware/IOChannel.cpp @@ -0,0 +1,235 @@ +#include "IOChannel.h" + +#ifdef HELLO_IM_A_PC +#include "asprintf.h" // use asprintf from libsmb2 +#endif /* HELLO_IM_A_PC */ + +#include + +size_t IOChannel::available() +{ + if (!_fifo.size()) + updateFIFO(); + return _fifo.size(); +} + +size_t IOChannel::dataIn(void *buffer, size_t length) +{ + size_t rlen, total = 0; + uint8_t *ptr; + uint64_t now, start; + + ptr = (uint8_t *) buffer; + now = start = GET_TIMESTAMP(); + while (length - total) + { + now = GET_TIMESTAMP(); + if (now - start > read_timeout_ms * 1000) + break; + rlen = std::min(length - total, available()); + if (!rlen) + continue; + memcpy(&ptr[total], _fifo.data(), rlen); + _fifo.erase(0, rlen); + total += rlen; + + // We received data, reset timeout + start = now; + } + + return total; +} + +void IOChannel::discardInput() +{ + uint64_t now, start; + + _fifo.clear(); + now = start = GET_TIMESTAMP(); + while (now - start < discard_timeout_ms * 1000) + { + now = GET_TIMESTAMP(); + if (available()) + { + _fifo.clear(); + start = now; + } + } + + return; +} + +size_t IOChannel::read(void *buffer, size_t length) +{ + return dataIn(buffer, length); +} + +int IOChannel::read(void) +{ + uint8_t buf[1]; + int result = read(buf, 1); + + if (result < 1) + return result; + return buf[0]; +} + +size_t IOChannel::write(const void *buffer, size_t length) +{ + return dataOut(buffer, length); +} + +size_t IOChannel::write(uint8_t c) +{ + uint8_t buf[1]; + + + buf[0] = c; + return write(buf, 1); +} + +size_t IOChannel::write(const char *s) +{ + return write(s, strlen(s)); +} + +size_t IOChannel::write(unsigned long n) +{ + return write((uint8_t) n); +} + +size_t IOChannel::write(long n) +{ + return write((uint8_t) n); +} + +size_t IOChannel::write(unsigned int n) +{ + return write((uint8_t) n); +} + +size_t IOChannel::write(int n) +{ + return write((uint8_t) n); +} + +size_t IOChannel::printf(const char *fmt...) +{ + char *result = nullptr; + va_list vargs; + + va_start(vargs, fmt); + + int z = vasprintf(&result, fmt, vargs); + + if (z > 0) + write(result, z); + + va_end(vargs); + + if (result != nullptr) + free(result); + + return z >= 0 ? z : 0; +} + +size_t IOChannel::_print_number(unsigned long n, uint8_t base) +{ + char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if (base < 2) + base = 10; + + do + { + unsigned long m = n; + n /= base; + char c = m - base * n; + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while (n); + + return write(str); +} + +size_t IOChannel::print(const char *str) +{ + int z = strlen(str); + + return write(str, z); + ; +} + +size_t IOChannel::print(const std::string &str) +{ + return print(str.c_str()); +} + +size_t IOChannel::print(int n, int base) +{ + return print((long)n, base); +} + +size_t IOChannel::print(unsigned int n, int base) +{ + return print((unsigned long)n, base); +} + +size_t IOChannel::print(long n, int base) +{ + if (base == 0) + { + return write(n); + } + else if (base == 10) + { + if (n < 0) + { + int t = print('-'); + n = -n; + return _print_number(n, 10) + t; + } + return _print_number(n, 10); + } + else + { + return _print_number(n, base); + } +} + +size_t IOChannel::print(unsigned long n, int base) +{ + if (base == 0) + { + return write(n); + } + else + { + return _print_number(n, base); + } +} + +size_t IOChannel::println(const char *str) +{ + size_t n = print(str); + n += println(); + return n; +} + +size_t IOChannel::println(std::string str) +{ + size_t n = print(str); + n += println(); + return n; +} + +size_t IOChannel::println(int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + diff --git a/lib/hardware/IOChannel.h b/lib/hardware/IOChannel.h new file mode 100644 index 000000000..41db06a64 --- /dev/null +++ b/lib/hardware/IOChannel.h @@ -0,0 +1,97 @@ +#ifndef IOCHANNEL_H +#define IOCHANNEL_H + +#define IOCHANNEL_DEFAULT_TIMEOUT 100 + +#ifndef ESP_PLATFORM +#if defined(_WIN16) || defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) +#define HELLO_IM_A_PC +#else /* ! (_WIN16 || _WIN32 || _WIN64 || __WINDOWS__ */ +#define ITS_A_UNIX_SYSTEM_I_KNOW_THIS +#endif /* ! (_WIN16 || _WIN32 || _WIN64 || __WINDOWS__ */ +#endif /* ESP_PLATFORM */ + +#include +#include +#include +#include + +#ifdef ESP_PLATFORM +#include +#define GET_TIMESTAMP() esp_timer_get_time() +#else /* ! ESP_PLATFORM */ +#include + +inline uint64_t GET_TIMESTAMP() { + auto now = std::chrono::steady_clock::now(); + auto micros = + std::chrono::duration_cast(now.time_since_epoch()); + return micros.count(); +} +#endif /* ESP_PLATFORM */ + +class IOChannel +{ +private: + size_t _print_number(unsigned long n, uint8_t base); + +protected: + std::string _fifo; + uint32_t read_timeout_ms = IOCHANNEL_DEFAULT_TIMEOUT; + uint32_t discard_timeout_ms = IOCHANNEL_DEFAULT_TIMEOUT; + + // Handled by IOChannel, not implemented by subclass + size_t dataIn(void *buffer, size_t length); + + // Must be implemented by subclass + virtual size_t dataOut(const void *buffer, size_t length) = 0; + virtual void updateFIFO() = 0; + +public: + // begin() and arguments vary by subclass so not declared here + virtual void end() = 0; + + virtual void flushOutput() = 0; + +#ifdef RS232_THINGS + virtual uint32_t getBaudrate() = 0; + virtual void setBaudrate(uint32_t baud) = 0; + + virtual bool getDTR() = 0; + virtual void setDSR(bool state) = 0; + virtual bool getRTS() = 0; + virtual void setCTS(bool state) = 0; +#endif /* RS232_THINGS */ + + // Handled by IOChannel, not implemented by subclass + size_t available(); + void discardInput(); + + /* Convenience methods, just wrappers for dataIn()/dataOut() methods above */ + size_t read(void *buffer, size_t length); + int read(void); + + size_t write(const void *buffer, size_t length); + size_t write(uint8_t c); + size_t write(const char *s); + size_t write(unsigned long n); + size_t write(long n); + size_t write(unsigned int n); + size_t write(int n); + + size_t printf(const char *format, ...); + + size_t println(const char *str); + size_t println() { return print("\r\n"); }; + size_t println(std::string str); + size_t println(int num, int base = 10); + + size_t print(const char *str); + size_t print(const std::string &str); + size_t print(int n, int base = 10); + size_t print(unsigned int n, int base = 10); + size_t print(long n, int base = 10); + size_t print(unsigned long n, int base = 10); +}; + +#endif /* IOCHANNEL_H */ diff --git a/lib/hardware/RS232ChannelProtocol.h b/lib/hardware/RS232ChannelProtocol.h new file mode 100644 index 000000000..f143ee2e3 --- /dev/null +++ b/lib/hardware/RS232ChannelProtocol.h @@ -0,0 +1,17 @@ +#ifndef RS232CHANNELPROTOCOL_H +#define RS232CHANNELPROTOCOL_H + +class RS232ChannelProtocol +{ +public: + virtual uint32_t getBaudrate() = 0; + virtual void setBaudrate(uint32_t baud) = 0; + + virtual bool getDTR() = 0; + virtual void setDSR(bool state) = 0; + virtual bool getRTS() = 0; + virtual void setCTS(bool state) = 0; + virtual bool getRI() = 0; +}; + +#endif /* RS232CHANNELPROTOCOL_H */ diff --git a/lib/hardware/TTYChannel.cpp b/lib/hardware/TTYChannel.cpp new file mode 100644 index 000000000..8b313f5ab --- /dev/null +++ b/lib/hardware/TTYChannel.cpp @@ -0,0 +1,403 @@ +#include "TTYChannel.h" + +#ifdef ITS_A_UNIX_SYSTEM_I_KNOW_THIS + +#include // Contains file controls like O_RDWR +#include + +#if defined(__linux__) +#include +#include "linux_termios2.h" +#elif defined(__APPLE__) +#include +#include +#endif + +#include "../../include/debug.h" + +#define TTY_PROBE_DEV1 "/dev/ttyUSB0" +#define TTY_PROBE_DEV2 "/dev/ttyS0" + +void TTYChannel::begin(const ChannelConfig& conf) +{ + if (_fd >= 0) + end(); + + _device = conf.device; + read_timeout_ms = conf.read_timeout_ms; + discard_timeout_ms = conf.discard_timeout_ms; + if (_device.empty()) + { + bool found = false; + for (const auto& probe : {TTY_PROBE_DEV1, TTY_PROBE_DEV2}) + { + Debug_printf("Trying %s\n", probe); + if ((_fd = open(probe, O_RDWR | O_NOCTTY | O_NONBLOCK)) >= 0) + { + _device = probe; + found = true; + break; + } + } + + if (found) + Debug_printf("Setting up serial port %s\n", _device.c_str()); + } + else + { + Debug_printf("Setting up serial port %s\n", _device.c_str()); + _fd = open(_device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); + } + + if (_fd < 0) + { + Debug_printf("Failed to open serial port, error %d: %s\n", errno, strerror(errno)); + return; + } + +#if defined(__linux__) + // Enable low latency + struct serial_struct ss; + if (ioctl(_fd, TIOCGSERIAL, &ss) == -1) + { + Debug_printf("TTY warning: TIOCGSERIAL failed: %d - %s\n", errno, strerror(errno)); + } + else + { + ss.flags |= ASYNC_LOW_LATENCY; + if (ioctl(_fd, TIOCSSERIAL, &ss) == -1) + Debug_printf("TTY warning: TIOCSSERIAL failed: %d - %s\n", errno, strerror(errno)); + } +#endif + + // Read in existing settings + struct termios tios; + if(tcgetattr(_fd, &tios) != 0) + { + Debug_printf("tcgetattr error %d: %s\n", errno, strerror(errno)); + return; + } + + tios.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common) + tios.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common) + tios.c_cflag &= ~CSIZE; // Clear all bits that set the data size + tios.c_cflag |= CS8; // 8 bits per byte (most common) + tios.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common) + tios.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1) + + tios.c_lflag &= ~ICANON; + tios.c_lflag &= ~ECHO; // Disable echo + tios.c_lflag &= ~ECHOE; // Disable erasure + tios.c_lflag &= ~ECHONL; // Disable new-line echo + tios.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP + tios.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl + tios.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes + + tios.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars) + tios.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed + // tios.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX) + // tios.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX) + + tios.c_cc[VTIME] = 0; + tios.c_cc[VMIN] = 0; + + // Apply settings + if (tcsetattr(_fd, TCSANOW, &tios) != 0) + { + Debug_printf("tcsetattr error %d: %s\n", errno, strerror(errno)); + return; + } + + Debug_printf("### TTY initialized ###\n"); + setBaudrate(conf.baud_rate); + + return; +} + +void TTYChannel::end() +{ + if (_fd >= 0) + { + close(_fd); + _fd = -1; + Debug_printf("### TTY stopped ###\n"); + } + + return; +} + +void TTYChannel::updateFIFO() +{ + int avail = 0; + + if (ioctl(_fd, FIONREAD, &avail) == -1) + return; + if (!avail) + return; + + size_t old_len = _fifo.size(); + _fifo.resize(old_len + avail); + int result = ::read(_fd, &_fifo[old_len], avail); + if (result < 0) + result = 0; + _fifo.resize(old_len + result); + + return; +} + +timeval timeval_from_ms(const uint32_t millis) +{ + timeval tv; + tv.tv_sec = millis / 1000; + tv.tv_usec = (millis - (tv.tv_sec * 1000)) * 1000; + return tv; +} + +size_t TTYChannel::dataOut(const void *buffer, size_t length) +{ + int result; + int txbytes; + fd_set writefds; + timeval timeout_tv(timeval_from_ms(500)); + + for (txbytes=0; txbytes 0) + { + // Make sure our file descriptor is in the ready to write list + if (FD_ISSET(_fd, &writefds)) + { + // This will write some + result = ::write(_fd, &((uint8_t *)buffer)[txbytes], length-txbytes); + // Debug_printf("write: %d\n", result); + if (result < 1) + { + Debug_printf("TTY write() write error %d: %s\n", errno, strerror(errno)); + break; + } + + txbytes += result; + if (txbytes == length) + { + // TODO is flush missing somewhere else? + // wait TTY is writable again before return + timeout_tv = timeval_from_ms(1000 + result * 12500 / _baud); + select(_fd + 1, NULL, &writefds, NULL, &timeout_tv); + // done + break; + } + if (txbytes < length) + { + timeout_tv = timeval_from_ms(1000 + result * 12500 / _baud); + continue; + } + } + // This shouldn't happen, if r > 0 our fd has to be in the list! + Debug_println("TTY write() unexpected select result"); + } + } + return txbytes; +} + +void TTYChannel::flushOutput() +{ + tcdrain(_fd); + return; +} + +void TTYChannel::setBaudrate(uint32_t baud) +{ + Debug_printf("TTY set_baudrate: %d\n", baud); + + if (baud == 0) + baud = 19200; + + int baud_id = B0; // B0 to indicate custom speed + + // map baudrate to predefined constant + switch (baud) + { + case 300: + baud_id = B300; + break; + case 600: + baud_id = B600; + break; + case 1200: + baud_id = B1200; + break; + case 1800: + baud_id = B1800; + break; + case 2400: + baud_id = B2400; + break; + case 4800: + baud_id = B4800; + break; + case 9600: + baud_id = B9600; + break; + case 19200: + baud_id = B19200; + break; + case 38400: + baud_id = B38400; + break; + case 57600: + baud_id = B57600; + break; + case 115200: + baud_id = B115200; + break; + } + + if (baud_id == B0) + { + // custom baud rate +#if defined(__APPLE__) && defined (IOSSIOSPEED) + // OS X support + + speed_t new_baud = (speed_t) baud; + if (-1 == ioctl(_fd, IOSSIOSPEED, &new_baud, 1)) + Debug_printf("IOSSIOSPEED error %d: %s\n", errno, strerror(errno)); + +#elif defined(__linux__) + // Linux Support + + struct termios2 tios2; + + if (-1 == ioctl(_fd, TCGETS2, &tios2)) + { + Debug_printf("TCGETS2 error %d: %s\n", errno, strerror(errno)); + return; + } + tios2.c_cflag &= ~(CBAUD | CBAUD << LINUX_IBSHIFT); + tios2.c_cflag |= BOTHER | BOTHER << LINUX_IBSHIFT; + tios2.c_ispeed = baud; + tios2.c_ospeed = baud; + if (-1 == ioctl(_fd, TCSETS2, &tios2)) + Debug_printf("TCSETS2 error %d: %s\n", errno, strerror(errno)); +#else + Debug_println("Custom baud rate is not implemented"); +#endif + } + else + { + // standard speeds + termios tios; + if(tcgetattr(_fd, &tios) != 0) + Debug_printf("tcgetattr error %d: %s\n", errno, strerror(errno)); + cfsetspeed(&tios, baud_id); + // Apply settings + if (tcsetattr(_fd, TCSANOW, &tios) != 0) + Debug_printf("tcsetattr error %d: %s\n", errno, strerror(errno)); + } + _baud = baud; +} + +#ifdef UNUSED +// FIXME - why does this function exist? Shouldn't the caller use begin()? +void TTYChannel::setPort(std::string device) +{ + Debug_printv("%s", device.c_str()); + _device = device; + return; +} +#endif /* UNUSED */ + +std::string TTYChannel::getPort() +{ + return _device; +} + +bool TTYChannel::getDTR() +{ + int status; + + if (ioctl(_fd, TIOCMGET, &status) == -1) + return false; + + return !!(status & TIOCM_DSR); +} + +void TTYChannel::setDSR(bool state) +{ + int status; + + if (state == _dtrState) + return; + if (ioctl(_fd, TIOCMGET, &status) == -1) + return; + + _dtrState = state; + status &= ~TIOCM_DTR; + if (_dtrState) + status |= TIOCM_DTR; + ioctl(_fd, TIOCMSET, &status); + return; +} + +bool TTYChannel::getRTS() +{ + int status; + + if (ioctl(_fd, TIOCMGET, &status) == -1) + return false; + + return !!(status & TIOCM_CTS); +} + +void TTYChannel::setCTS(bool state) +{ + int status; + + if (state == _rtsState) + return; + if (ioctl(_fd, TIOCMGET, &status) == -1) + return; + + _rtsState = state; + status &= ~TIOCM_RTS; + if (_rtsState) + status |= TIOCM_RTS; + ioctl(_fd, TIOCMSET, &status); + return; +} + +bool TTYChannel::getRI() +{ + int status; + + if (ioctl(_fd, TIOCMGET, &status) == -1) + return false; + + return !!(status & TIOCM_RI); +} + +#endif /* ITS_A_UNIX_SYSTEM_I_KNOW_THIS */ diff --git a/lib/hardware/TTYChannel.h b/lib/hardware/TTYChannel.h new file mode 100644 index 000000000..b03ace493 --- /dev/null +++ b/lib/hardware/TTYChannel.h @@ -0,0 +1,67 @@ +#ifndef TTYCHANNEL_H +#define TTYCHANNEL_H + +#include "IOChannel.h" +#include "RS232ChannelProtocol.h" + +#ifdef ITS_A_UNIX_SYSTEM_I_KNOW_THIS + +#define FN_UART_BUS "" + +struct ChannelConfig +{ + std::string device; + int baud_rate; + uint32_t read_timeout_ms = IOCHANNEL_DEFAULT_TIMEOUT; + uint32_t discard_timeout_ms = IOCHANNEL_DEFAULT_TIMEOUT; + + ChannelConfig& baud(int baud) { + baud_rate = baud; return *this; + } + ChannelConfig& deviceID(std::string path) { + device = path; return *this; + } + ChannelConfig& readTimeout(uint32_t millis) { + read_timeout_ms = millis; return *this; + } + ChannelConfig& discardTimeout(uint32_t millis) { + discard_timeout_ms = millis; return *this; + } +}; + +class TTYChannel : public IOChannel, public RS232ChannelProtocol +{ +private: + int _fd = -1; + std::string _device; + uint32_t _baud; + bool _dtrState = true, _rtsState = true; + +protected: + void updateFIFO() override; + size_t dataOut(const void *buffer, size_t length) override; + +public: + void begin(const ChannelConfig& conf); + void end() override; + + void flushOutput() override; + + uint32_t getBaudrate() override { return _baud; } + void setBaudrate(uint32_t baud) override; + + // FujiNet acts as modem (DCE), computer serial ports are DTE. + // API names follow the modem (DCE) view, but the actual RS-232 pin differs. + bool getDTR() override; // modem DTR input → actually reads RS-232 DSR pin + void setDSR(bool state) override; // modem DSR output → actually drives RS-232 DTR pin + bool getRTS() override; // modem RTS input → actually reads RS-232 CTS pin + void setCTS(bool state) override; // modem CTS output → actually drives RS-232 RTS pin + bool getRI() override; // Ring Indicator is only an input on DTE :-/ + + void setPort(std::string device); + std::string getPort(); +}; + +#endif /* ITS_A_UNIX_SYSTEM_I_KNOW_THIS */ + +#endif /* TTYCHANNEL_H */ diff --git a/lib/hardware/UARTChannel.h b/lib/hardware/UARTChannel.h new file mode 100644 index 000000000..15387d303 --- /dev/null +++ b/lib/hardware/UARTChannel.h @@ -0,0 +1,18 @@ +#ifndef UARTCHANNEL_H +#define UARTCHANNEL_H + +#include "ESP32UARTChannel.h" +#include "TTYChannel.h" +#include "COMChannel.h" + +#if defined(ITS_A_UNIX_SYSTEM_I_KNOW_THIS) +using UARTChannel = TTYChannel; +#elif defined(HELLO_IM_A_PC) +using UARTChannel = COMChannel; +#elif defined(ESP_PLATFORM) +using UARTChannel = ESP32UARTChannel; +#else +#error "Unknown serial hardware" +#endif + +#endif /* UARTCHANNEL_H */ diff --git a/lib/hardware/fnUART.cpp b/lib/hardware/fnUART.cpp deleted file mode 100644 index ebaf53f88..000000000 --- a/lib/hardware/fnUART.cpp +++ /dev/null @@ -1,558 +0,0 @@ -#ifdef ESP_PLATFORM - -// ESP UART code - - -#include "fnUART.h" -#include "fnSystem.h" - -#include -#include - -#include - -#include "../../include/pinmap.h" - -#include "../../include/debug.h" - -// Number of RTOS ticks to wait for data in TX buffer to complete sending -#define MAX_FLUSH_WAIT_TICKS 200 -#define MAX_READ_WAIT_TICKS 200 -#define MAX_WRITE_BYTE_TICKS 100 -#define MAX_WRITE_BUFFER_TICKS 1000 - -// Serial "debug port" -UARTManager fnDebugConsole(FN_UART_DEBUG); - -// Constructor -UARTManager::UARTManager(uart_port_t uart_num) : _uart_num(uart_num), _uart_q(NULL) {} - -void UARTManager::end() -{ - uart_driver_delete(_uart_num); - if (_uart_q) - vQueueDelete(_uart_q); - _uart_q = NULL; -} - -void UARTManager::begin(int baud) -{ - if (_uart_q) - { - end(); - } - - uart_config_t uart_config; - memset(&uart_config, 0, sizeof(uart_config)); - uart_config.baud_rate = baud; - uart_config.data_bits = UART_DATA_8_BITS; -#ifdef BUILD_LYNX - uart_config.parity = UART_PARITY_ODD; -#else - uart_config.parity = UART_PARITY_DISABLE; -#endif /* BUILD_LYNX */ - uart_config.stop_bits = UART_STOP_BITS_1; - uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; - uart_config.rx_flow_ctrl_thresh = 122; // No idea what this is for, but shouldn't matter if flow ctrl is disabled? -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) - uart_config.source_clk = UART_SCLK_DEFAULT; -#else - uart_config.use_ref_tick = false; // ? -#endif - - // This works around an obscure hardware bug where resetting UART2 causes the TX to become corrupted - // when the FIFO is reset by this function. Blame me for it -Thom - // ... except on the Adam, which needs this to happen regardless. Go figure. -// #ifdef BUILD_ATARI -// if (_uart_num == UART_SIO) -// { -// if (esp_reset_reason() != ESP_RST_SW) -// uart_param_config(_uart_num, &uart_config); -// } -// else if (_uart_num == UART_DEBUG) -// { -// uart_param_config(_uart_num, &uart_config); -// } -// #else - uart_param_config(_uart_num, &uart_config); // now always gets called. -// #endif - - int tx, rx; - if (_uart_num == 0) - { - rx = PIN_UART0_RX; - tx = PIN_UART0_TX; - } - else if (_uart_num == 1) - { - rx = PIN_UART1_RX; - tx = PIN_UART1_TX; - } -#ifndef BUILD_RS232 - else if (_uart_num == 2) - { - rx = PIN_UART2_RX; - tx = PIN_UART2_TX; - } -#endif /* BUILD_RS232 */ - else - { - return; - } - - uart_set_pin(_uart_num, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - -#ifdef BUILD_ADAM - if (_uart_num == 2) - uart_set_line_inverse(_uart_num, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV); -#endif /* BUILD_ADAM */ - -#ifdef BUILD_COCO // do invert for coco builds -#ifndef PINMAP_COCO_CART // do not invert for coco carts -#ifndef PINMAP_FOENIX_OS9_D32PRO // do not invert for Foenix - if (_uart_num == 2) - { - // Start in DRIVEWIRE mode - // Set the initial buad rate based on which ROM image is selected by the A14/A15 dip switch on Rev000 or newer. - // If using an older Rev0 or Rev00 board, you will need to pull PIN_EPROM_A14 (IO36) up to 3.3V or 5V via a 10K - // resistor to have it default to the previous default of 57600 baud otherwise they will both read as low and you - // will get 38400 baud. - - fnSystem.set_pin_mode(PIN_EPROM_A14, gpio_mode_t::GPIO_MODE_INPUT, SystemManager::pull_updown_t::PULL_NONE); - fnSystem.set_pin_mode(PIN_EPROM_A15, gpio_mode_t::GPIO_MODE_INPUT, SystemManager::pull_updown_t::PULL_NONE); - - if (fnSystem.digital_read(PIN_EPROM_A14) == DIGI_HIGH && fnSystem.digital_read(PIN_EPROM_A15) == DIGI_HIGH) - { - - // uart_set_line_inverse(_uart_num, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV); - uart_set_line_inverse(_uart_num, UART_SIGNAL_RXD_INV); - - Debug_printf("Dragon mode, set uart %d to RXD inverse.\r\n", _uart_num); - } - else - { - uart_set_line_inverse(_uart_num, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV); - } - } -#endif /* PINMAP_FOENIX_OS9_D32PRO */ -#endif /* PINMAP_COCO_CART */ -#endif /* BUILD_COCO */ - - - // Arduino default buffer size is 256 - int uart_buffer_size = 256; - int uart_queue_size = 10; - int intr_alloc_flags = 0; - - // Install UART driver using an event queue here - // uart_driver_install(_uart_num, uart_buffer_size, uart_buffer_size, uart_queue_size, &_uart_q, intr_alloc_flags); - uart_driver_install(_uart_num, uart_buffer_size, 0, uart_queue_size, NULL, intr_alloc_flags); - -#ifdef BUILD_ADAM - uart_intr_config_t uart_intr; - uart_intr.intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M | UART_FRM_ERR_INT_ENA_M | UART_RXFIFO_OVF_INT_ENA_M | UART_BRK_DET_INT_ENA_M | UART_PARITY_ERR_INT_ENA_M; - uart_intr.rxfifo_full_thresh = 1; // UART_FULL_THRESH_DEFAULT, //120 default!! aghh! need receive 120 chars before we see them - uart_intr.rx_timeout_thresh = 10; // UART_TOUT_THRESH_DEFAULT, //10 works well for my short messages I need send/receive - uart_intr.txfifo_empty_intr_thresh = 2; // UART_EMPTY_THRESH_DEFAULT - uart_intr_config(_uart_num, &uart_intr); -#endif /* BUILD_ADAM */ - -#ifdef BUILD_LYNX - uart_intr_config_t uart_intr; - uart_intr.intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M | UART_FRM_ERR_INT_ENA_M | UART_RXFIFO_OVF_INT_ENA_M | UART_BRK_DET_INT_ENA_M | UART_PARITY_ERR_INT_ENA_M; - uart_intr.rxfifo_full_thresh = 1; // UART_FULL_THRESH_DEFAULT, //120 default!! aghh! need receive 120 chars before we see them - uart_intr.rx_timeout_thresh = 10; // UART_TOUT_THRESH_DEFAULT, //10 works well for my short messages I need send/receive - uart_intr.txfifo_empty_intr_thresh = 2; // UART_EMPTY_THRESH_DEFAULT - uart_intr_config(_uart_num, &uart_intr); -#endif /* BUILD_LYNX */ - - // Set initialized. - _initialized = true; -} - -/* Discards anything in the input buffer - */ -void UARTManager::flush_input() -{ - uart_flush_input(_uart_num); -} - -/* Clears input buffer and flushes out transmit buffer waiting at most - waiting MAX_FLUSH_WAIT_TICKS until all sends are completed -*/ -void UARTManager::flush() -{ - uart_wait_tx_done(_uart_num, MAX_FLUSH_WAIT_TICKS); -} - -/* Returns number of bytes available in receive buffer or -1 on error - */ -int UARTManager::available() -{ - size_t result; - if (ESP_FAIL == uart_get_buffered_data_len(_uart_num, &result)) - return -1; - return result; -} - -/* NOT IMPLEMENTED - */ -int UARTManager::peek() -{ - return 0; -} - -/* Get current baud rate -*/ -uint32_t UARTManager::get_baudrate() -{ - uint32_t baud; - uart_get_baudrate(_uart_num, &baud); - return baud; -} - -/* Changes baud rate - */ -void UARTManager::set_baudrate(uint32_t baud) -{ -#ifdef DEBUG - uint32_t before; - uart_get_baudrate(_uart_num, &before); -#endif - uart_set_baudrate(_uart_num, baud); -#ifdef DEBUG - Debug_printf("set_baudrate change from %d to %d\r\n", before, baud); -#endif -} - -/* Returns a single byte from the incoming stream - */ -int UARTManager::read(void) -{ - uint8_t byte; - int result = uart_read_bytes(_uart_num, &byte, 1, MAX_READ_WAIT_TICKS); - if (result < 1) - { -#ifdef DEBUG - if (result == 0) - { - Debug_println("### UART read() TIMEOUT ###"); - } - else - { - Debug_printf("### UART read() ERROR %d ###\r\n", result); - } -#endif - return -1; - } - else - { - return byte; - } -} - -/* Since the underlying Stream calls this Read() multiple times to get more than one - * character for ReadBytes(), we override with a single call to uart_read_bytes - */ -size_t UARTManager::readBytes(void *buffer, size_t length) -{ - int result = uart_read_bytes(_uart_num, buffer, length, MAX_READ_WAIT_TICKS); -#ifdef DEBUG - if (result < length) - { - if (result < 0) - { - Debug_printf("### UART readBytes() ERROR %d ###\r\n", result); - } - else - { - // Debug_println("### UART readBytes() TIMEOUT ###"); - } - } -#endif - return result; -} - -size_t UARTManager::write(uint8_t c) -{ - int z = uart_write_bytes(_uart_num, (const char *)&c, 1); - // uart_wait_tx_done(_uart_num, MAX_WRITE_BYTE_TICKS); - return z; -} - -size_t UARTManager::write(const void *buffer, size_t size) -{ - int z = uart_write_bytes(_uart_num, (const char *)buffer, size); - // uart_wait_tx_done(_uart_num, MAX_WRITE_BUFFER_TICKS); - return z; -} - -size_t UARTManager::write(const char *str) -{ - int z = uart_write_bytes(_uart_num, str, strlen(str)); - return z; -} - -size_t UARTManager::printf(const char *fmt...) -{ - char *result = nullptr; - va_list vargs; - - if (!_initialized) - return -1; - - va_start(vargs, fmt); - - int z = vasprintf(&result, fmt, vargs); - - if (z > 0) - uart_write_bytes(_uart_num, result, z); - - va_end(vargs); - - if (result != nullptr) - free(result); - - // uart_wait_tx_done(_uart_num, MAX_WRITE_BUFFER_TICKS); - - return z >= 0 ? z : 0; -} - -size_t UARTManager::_print_number(unsigned long n, uint8_t base) -{ - char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. - char *str = &buf[sizeof(buf) - 1]; - - if (!_initialized) - return -1; - - *str = '\0'; - - // prevent crash if called with base == 1 - if (base < 2) - base = 10; - - do - { - unsigned long m = n; - n /= base; - char c = m - base * n; - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while (n); - - return write(str); -} - -size_t UARTManager::print(const char *str) -{ - int z = strlen(str); - - if (!_initialized) - return -1; - - return uart_write_bytes(_uart_num, str, z); - ; -} - -size_t UARTManager::print(const std::string &str) -{ - if (!_initialized) - return -1; - - return print(str.c_str()); -} - -size_t UARTManager::print(int n, int base) -{ - if (!_initialized) - return -1; - - return print((long)n, base); -} - -size_t UARTManager::print(unsigned int n, int base) -{ - if (!_initialized) - return -1; - - return print((unsigned long)n, base); -} - -size_t UARTManager::print(long n, int base) -{ - if (!_initialized) - return -1; - - if (base == 0) - { - return write(n); - } - else if (base == 10) - { - if (n < 0) - { - int t = print('-'); - n = -n; - return _print_number(n, 10) + t; - } - return _print_number(n, 10); - } - else - { - return _print_number(n, base); - } -} - -size_t UARTManager::print(unsigned long n, int base) -{ - if (!_initialized) - return -1; - - if (base == 0) - { - return write(n); - } - else - { - return _print_number(n, base); - } -} - -size_t UARTManager::println(const char *str) -{ - if (!_initialized) - return -1; - - size_t n = print(str); - n += println(); - return n; -} - -size_t UARTManager::println(std::string str) -{ - if (!_initialized) - return -1; - - size_t n = print(str); - n += println(); - return n; -} - -size_t UARTManager::println(int num, int base) -{ - if (!_initialized) - return -1; - - size_t n = print(num, base); - n += println(); - return n; -} - -/* - -size_t Print::print(const __FlashStringHelper *ifsh) -{ - return print(reinterpret_cast(ifsh)); -} - - -size_t Print::print(char c) -{ - return write(c); -} - -size_t Print::print(unsigned char b, int base) -{ - return print((unsigned long) b, base); -} - - -size_t Print::print(double n, int digits) -{ - return printFloat(n, digits); -} - -size_t Print::println(const __FlashStringHelper *ifsh) -{ - size_t n = print(ifsh); - n += println(); - return n; -} - -size_t Print::print(const Printable& x) -{ - return x.printTo(*this); -} - -size_t Print::print(struct tm * timeinfo, const char * format) -{ - const char * f = format; - if(!f){ - f = "%c"; - } - char buf[64]; - size_t written = strftime(buf, 64, f, timeinfo); - if(written == 0){ - return written; - } - return print(buf); -} - -size_t Print::println(char c) -{ - size_t n = print(c); - n += println(); - return n; -} - -size_t Print::println(unsigned char b, int base) -{ - size_t n = print(b, base); - n += println(); - return n; -} - -size_t Print::println(unsigned int num, int base) -{ - size_t n = print(num, base); - n += println(); - return n; -} - -size_t Print::println(long num, int base) -{ - size_t n = print(num, base); - n += println(); - return n; -} - -size_t Print::println(unsigned long num, int base) -{ - size_t n = print(num, base); - n += println(); - return n; -} - -size_t Print::println(double num, int digits) -{ - size_t n = print(num, digits); - n += println(); - return n; -} - -size_t Print::println(const Printable& x) -{ - size_t n = print(x); - n += println(); - return n; -} - -size_t Print::println(struct tm * timeinfo, const char * format) -{ - size_t n = print(timeinfo, format); - n += println(); - return n; -} -*/ - -#endif // ESP_PLATFORM diff --git a/lib/hardware/fnUART.h b/lib/hardware/fnUART.h deleted file mode 100644 index 90d70090e..000000000 --- a/lib/hardware/fnUART.h +++ /dev/null @@ -1,164 +0,0 @@ -/* Basically a simplified copy of the ESP Arduino library in HardwareSerial.h/HardwareSerial.cpp -*/ -#ifndef FNUART_H -#define FNUART_H - -#ifdef ESP_PLATFORM -# include -# define FN_UART_DEBUG UART_NUM_0 -# if defined(BUILD_RS232) || defined(PINMAP_COCO_ESP32S3) -# define FN_UART_BUS UART_NUM_1 -# else -# define FN_UART_BUS UART_NUM_2 -# endif -#endif // ESP_PLATFORM - -#if defined (_WIN32) -// The inclusion of windows.h is causing compiler warnings where winsock2 is also needed, so added it here as most -// code that includes fnUART uses winsock2 -#include -#include -#endif - -#include -#include - - -class UARTManager -{ -private: -#ifdef ESP_PLATFORM - uart_port_t _uart_num; - QueueHandle_t _uart_q; -#else - char _device[64]; // device name or path - uint32_t _baud; - int _command_pin; - int _proceed_pin; - -#if defined (_WIN32) - int _command_status; - int _proceed_set; - int _proceed_clear; - HANDLE _fd; -#else - int _command_tiocm; - int _proceed_tiocm; - int _fd; -#endif - // serial port error counter - int _errcount; - unsigned long _suspend_time; -#endif // !ESP_PLATFORM - - bool _initialized = false; // is UART ready? - - size_t _print_number(unsigned long n, uint8_t base); - -public: -#ifdef ESP_PLATFORM - UARTManager(uart_port_t uart_num = UART_NUM_0); - - void begin(int baud); - void end(); - uint32_t get_baudrate(); - void set_baudrate(uint32_t baud); - bool initialized() { return _initialized; } - - int available(); - int peek(); - void flush(); - void flush_input(); - - int read(); - size_t readBytes(void *buffer, size_t length); - size_t readBytes(char *buffer, size_t length) { return readBytes((uint8_t *)buffer, length); }; - - size_t write(uint8_t); - size_t write(const void *buffer, size_t size); - size_t write(const char *s); - - size_t write(unsigned long n) { return write((uint8_t)n); }; - size_t write(long n) { return write((uint8_t)n); }; - size_t write(unsigned int n) { return write((uint8_t)n); }; - size_t write(int n) { return write((uint8_t)n); }; - - size_t printf(const char *format, ...); - - //size_t println(const char *format, ...); - size_t println(const char *str); - size_t println() { return print("\r\n"); }; - size_t println(std::string str); - size_t println(int num, int base = 10); - - //size_t print(const char *format, ...); - size_t print(const char *str); - size_t print(const std::string &str); - size_t print(int n, int base = 10); - size_t print(unsigned int n, int base = 10); - size_t print(long n, int base = 10); - size_t print(unsigned long n, int base = 10); -#else - UARTManager(); - - void begin(int baud); - void end(); - bool poll(int ms); - - void suspend(int sec=5); - bool initialized() { return _initialized; } - - void set_port(const char *device, int command_pin=0, int proceed_pin=0); - const char* get_port(int *ptr_command_pin=nullptr, int *ptr_proceed_pin=nullptr); - - void set_baudrate(uint32_t baud); - uint32_t get_baudrate() { return _baud; } - - bool command_asserted(); - bool motor_asserted() { return false; } // not pin available - void set_proceed(bool level); - void set_interrupt(bool level) {} // not pin available - - int available(); - void flush(); - void flush_input(); - - bool waitReadable(uint32_t timeout_ms); - - int read(); - size_t readBytes(uint8_t *buffer, size_t length); - size_t readBytes(char *buffer, size_t length) { return readBytes((uint8_t *)buffer, length); } - - size_t write(uint8_t); - size_t write(const uint8_t *buffer, size_t size); - size_t write(const char *s); - - size_t write(unsigned long n) { return write((uint8_t)n); } - size_t write(long n) { return write((uint8_t)n); } - size_t write(unsigned int n) { return write((uint8_t)n); } - size_t write(int n) { return write((uint8_t)n); } - - // size_t printf(const char *format, ...); - - // //size_t println(const char *format, ...); - // size_t println(const char *str); - // size_t println() { return print("\r\n"); }; - // size_t println(std::string str); - // size_t println(int num, int base = 10); - - // //size_t print(const char *format, ...); - // size_t print(const char *str); - // size_t print(const std::string &str); - // size_t print(int n, int base = 10); - // size_t print(unsigned int n, int base = 10); - // size_t print(long n, int base = 10); - // size_t print(unsigned long n, int base = 10); -#endif // ESP_PLATFORM -}; - -#ifdef ESP_PLATFORM - // Serial "debug port" for FN-ESP (not available on FN-PC) - extern UARTManager fnDebugConsole; -#endif - -#endif //FNUART_H diff --git a/lib/hardware/fnUARTUnix.cpp b/lib/hardware/fnUARTUnix.cpp deleted file mode 100644 index 5d66b6b5f..000000000 --- a/lib/hardware/fnUARTUnix.cpp +++ /dev/null @@ -1,597 +0,0 @@ -#ifndef ESP_PLATFORM - -#if defined(__linux__) || defined(__APPLE__) - -// Linux and macOS UART code - -#include "fnUART.h" - -#include -#include -#include -#include -#include // write(), read(), close() -#include // Error integer and strerror() function -#include // Contains POSIX terminal control definitions -#include // TIOCM_DSR etc. -#include // Contains file controls like O_RDWR - -#if defined(__linux__) -#include -#include "linux_termios2.h" -#elif defined(__APPLE__) -#include -#endif - -#include "compat_string.h" -#include "fnSystem.h" - -#include "../../include/debug.h" - -#define UART_PROBE_DEV1 "/dev/ttyUSB0" -#define UART_PROBE_DEV2 "/dev/ttyS0" -#define UART_DEFAULT_BAUD 19200 - - -// Constructor -// UARTManager::UARTManager(uart_port_t uart_num) : _uart_num(uart_num), _uart_q(NULL) {} -UARTManager::UARTManager() : - _initialized(false), - _fd(-1), - _device{0}, - _baud(UART_DEFAULT_BAUD) -{}; - -void UARTManager::end() -{ - if (_fd >= 0) - { - close(_fd); - _fd = -1; - Debug_printf("### UART stopped ###\n"); - } - _initialized = false; -} - -bool UARTManager::poll(int ms) -{ - // TODO check serial port command link and input data - fnSystem.delay_microseconds(500); // TODO use ms parameter - return false; -} - -void UARTManager::set_port(const char *device, int command_pin, int proceed_pin) -{ - if (device != nullptr) - strlcpy(_device, device, sizeof(_device)); - - _command_pin = command_pin; - _proceed_pin = proceed_pin; - - switch (_command_pin) - { -// TODO move from fnConfig.h to fnUART.h -// enum serial_command_pin -// { -// SERIAL_COMMAND_NONE = 0, -// SERIAL_COMMAND_DSR, -// SERIAL_COMMAND_CTS, -// SERIAL_COMMAND_RI, -// SERIAL_COMMAND_INVALID -// }; - case 1: // SERIAL_COMMAND_DSR - _command_tiocm = TIOCM_DSR; - break; - case 2: // SERIAL_COMMAND_CTS - _command_tiocm = TIOCM_CTS; - break; - case 3: // SERIAL_COMMAND_RI - _command_tiocm = TIOCM_RI; - break; - default: - _command_tiocm = 0; - } - -// TODO move from fnConfig.h to fnUART.h -// enum serial_proceed_pin -// { -// SERIAL_PROCEED_NONE = 0, -// SERIAL_PROCEED_DTR, -// SERIAL_PROCEED_RTS, -// SERIAL_PROCEED_INVALID -// }; - switch (_proceed_pin) - { - case 1: // SERIAL_PROCEED_DTR - _proceed_tiocm = TIOCM_DTR; - break; - case 2: // SERIAL_PROCEED_RTS - _proceed_tiocm = TIOCM_RTS; - break; - default: - _proceed_tiocm = 0; - } -} - -const char* UARTManager::get_port(int *ptr_command_pin, int *ptr_proceed_pin) -{ - if (ptr_command_pin) - *ptr_command_pin = _command_pin; - if (ptr_proceed_pin) - *ptr_proceed_pin = _proceed_pin; - return _device; -} - -void UARTManager::begin(int baud) -{ - if(_initialized) - { - end(); - } - - _errcount = 0; - _suspend_time = 0; - - // Open the serial port - if (*_device == 0) - { - // Probe some serial ports - Debug_println("Trying " UART_PROBE_DEV1); - if ((_fd = open(UART_PROBE_DEV1, O_RDWR | O_NOCTTY | O_NONBLOCK)) >= 0) - strlcpy(_device, UART_PROBE_DEV1, sizeof(_device)); - else - { - Debug_println("Trying " UART_PROBE_DEV2); - if ((_fd = open(UART_PROBE_DEV2, O_RDWR | O_NOCTTY | O_NONBLOCK)) >= 0) - strlcpy(_device, UART_PROBE_DEV2, sizeof(_device)); - } - - // successful probe - if (*_device != 0) - Debug_printf("Setting up serial port %s\n", _device); - } - else - { - Debug_printf("Setting up serial port %s\n", _device); - _fd = open(_device, O_RDWR | O_NOCTTY | O_NONBLOCK); - } - - if (_fd < 0) - { - Debug_printf("Failed to open serial port, error %d: %s\n", errno, strerror(errno)); - suspend(); - return; - } - -#if defined(__linux__) - // Enable low latency - struct serial_struct ss; - if (ioctl(_fd, TIOCGSERIAL, &ss) == -1) - { - Debug_printf("UART warning: TIOCGSERIAL failed: %d - %s\n", errno, strerror(errno)); - } - else - { - ss.flags |= ASYNC_LOW_LATENCY; - if (ioctl(_fd, TIOCSSERIAL, &ss) == -1) - Debug_printf("UART warning: TIOCSSERIAL failed: %d - %s\n", errno, strerror(errno)); - } -#endif - - // Read in existing settings - struct termios tios; - if(tcgetattr(_fd, &tios) != 0) - { - Debug_printf("tcgetattr error %d: %s\n", errno, strerror(errno)); - suspend(); - return; - } - - tios.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common) - tios.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common) - tios.c_cflag &= ~CSIZE; // Clear all bits that set the data size - tios.c_cflag |= CS8; // 8 bits per byte (most common) - tios.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common) - tios.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1) - - tios.c_lflag &= ~ICANON; - tios.c_lflag &= ~ECHO; // Disable echo - tios.c_lflag &= ~ECHOE; // Disable erasure - tios.c_lflag &= ~ECHONL; // Disable new-line echo - tios.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP - tios.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl - tios.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes - - tios.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars) - tios.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed - // tios.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX) - // tios.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX) - - tios.c_cc[VTIME] = 0; - tios.c_cc[VMIN] = 0; - - // Apply settings - if (tcsetattr(_fd, TCSANOW, &tios) != 0) - { - Debug_printf("tcsetattr error %d: %s\n", errno, strerror(errno)); - suspend(); - return; - } - - Debug_printf("### UART initialized ###\n"); - // Set initialized. - _initialized = true; - set_baudrate(baud); -} - - -void UARTManager::suspend(int sec) -{ - Debug_println("Suspending serial port"); - struct timeval tv; - gettimeofday(&tv, NULL); - _suspend_time = tv.tv_sec + sec; - end(); -} - -/* Discards anything in the input buffer - */ -void UARTManager::flush_input() -{ - if (_initialized) - tcflush(_fd, TCIFLUSH); -} - -/* Clears input buffer and flushes out transmit buffer waiting at most - waiting MAX_FLUSH_WAIT_TICKS until all sends are completed -*/ -void UARTManager::flush() -{ - if (_initialized) - tcdrain(_fd); -} - -/* Returns number of bytes available in receive buffer or -1 on error - */ -int UARTManager::available() -{ - int result; - if (!_initialized) - return 0; - if (ioctl(_fd, FIONREAD, &result) < 0) - return 0; - return result; -} - -/* Changes baud rate -*/ -void UARTManager::set_baudrate(uint32_t baud) -{ - Debug_printf("UART set_baudrate: %d\n", baud); - - if (!_initialized) - return; - - if (baud == 0) - baud = 19200; - - int baud_id = B0; // B0 to indicate custom speed - - // map baudrate to predefined constant - switch (baud) - { - case 300: - baud_id = B300; - break; - case 600: - baud_id = B600; - break; - case 1200: - baud_id = B1200; - break; - case 1800: - baud_id = B1800; - break; - case 2400: - baud_id = B2400; - break; - case 4800: - baud_id = B4800; - break; - case 9600: - baud_id = B9600; - break; - case 19200: - baud_id = B19200; - break; - case 38400: - baud_id = B38400; - break; - case 57600: - baud_id = B57600; - break; - case 115200: - baud_id = B115200; - break; - } - - if (baud_id == B0) - { - // custom baud rate -#if defined(__APPLE__) && defined (IOSSIOSPEED) - // OS X support - - speed_t new_baud = (speed_t) baud; - if (-1 == ioctl(_fd, IOSSIOSPEED, &new_baud, 1)) - Debug_printf("IOSSIOSPEED error %d: %s\n", errno, strerror(errno)); - -#elif defined(__linux__) - // Linux Support - - struct termios2 tios2; - - if (-1 == ioctl(_fd, TCGETS2, &tios2)) - { - Debug_printf("TCGETS2 error %d: %s\n", errno, strerror(errno)); - return; - } - tios2.c_cflag &= ~(CBAUD | CBAUD << LINUX_IBSHIFT); - tios2.c_cflag |= BOTHER | BOTHER << LINUX_IBSHIFT; - tios2.c_ispeed = baud; - tios2.c_ospeed = baud; - if (-1 == ioctl(_fd, TCSETS2, &tios2)) - Debug_printf("TCSETS2 error %d: %s\n", errno, strerror(errno)); -#else - Debug_println("Custom baud rate is not implemented"); -#endif - } - else - { - // standard speeds - termios tios; - if(tcgetattr(_fd, &tios) != 0) - Debug_printf("tcgetattr error %d: %s\n", errno, strerror(errno)); - cfsetspeed(&tios, baud_id); - // Apply settings - if (tcsetattr(_fd, TCSANOW, &tios) != 0) - Debug_printf("tcsetattr error %d: %s\n", errno, strerror(errno)); - } - _baud = baud; -} - -bool UARTManager::command_asserted(void) -{ - int status; - - if (! _initialized) - { - // is serial port suspended ? - if (_suspend_time != 0) - { - struct timeval tv; - gettimeofday(&tv, NULL); - if (_suspend_time > tv.tv_sec) - return false; - // try to re-open serial port - begin(_baud); - } - if (! _initialized) - return false; - } - - if (ioctl(_fd, TIOCMGET, &status) < 0) - { - // handle serial port errors - _errcount++; - if(_errcount == 1) - Debug_printf("UART command_asserted() TIOCMGET error %d: %s\n", errno, strerror(errno)); - else if (_errcount > 1000) - suspend(); - return false; - } - _errcount = 0; - - return ((status & _command_tiocm) != 0); -} - -void UARTManager::set_proceed(bool level) -{ - static int last_level = -1; // 0,1 or -1 for unknown - int new_level = level ? 0 : 1; - int result; - - if (!_initialized) - return; - if (last_level == new_level) - return; - - Debug_print(level ? "+" : "-"); - last_level = new_level; - - unsigned long request = level ? TIOCMBIC : TIOCMBIS; - result = ioctl(_fd, request, &_proceed_tiocm); - if (result < 0) - Debug_printf("UART set_proceed() ioctl error %d: %s\n", errno, strerror(errno)); -} - -timeval timeval_from_ms(const uint32_t millis) -{ - timeval tv; - tv.tv_sec = millis / 1000; - tv.tv_usec = (millis - (tv.tv_sec * 1000)) * 1000; - return tv; -} - -bool UARTManager::waitReadable(uint32_t timeout_ms) -{ - // Setup a select call to block for serial data or a timeout - fd_set readfds; - FD_ZERO(&readfds); - FD_SET(_fd, &readfds); - timeval timeout_tv(timeval_from_ms(timeout_ms)); - - int result = select(_fd + 1, &readfds, nullptr, nullptr, &timeout_tv); - - if (result < 0) - { - if (errno != EINTR) - { - Debug_printf("UART waitReadable() select error %d: %s\n", errno, strerror(errno)); - } - return false; - } - // Timeout occurred - if (result == 0) - { - return false; - } - // This shouldn't happen, if result > 0 our fd has to be in the list! - if (!FD_ISSET (_fd, &readfds)) - { - Debug_println("UART waitReadable() unexpected select result"); - } - // Data available to read. - return true; -} - -/* Returns a single byte from the incoming stream - */ -int UARTManager::read(void) -{ - uint8_t byte; - return (readBytes(&byte, 1) == 1) ? byte : -1; -} - -/* Since the underlying Stream calls this Read() multiple times to get more than one - * character for ReadBytes(), we override with a single call to uart_read_bytes - */ -size_t UARTManager::readBytes(uint8_t *buffer, size_t length) -{ - if (!_initialized) - return 0; - - int result; - int rxbytes; - for (rxbytes=0; rxbytes 0) - { - // Make sure our file descriptor is in the ready to write list - if (FD_ISSET(_fd, &writefds)) - { - // This will write some - result = ::write(_fd, &buffer[txbytes], size-txbytes); - // Debug_printf("write: %d\n", result); - if (result < 1) - { - Debug_printf("UART write() write error %d: %s\n", errno, strerror(errno)); - break; - } - - txbytes += result; - if (txbytes == size) - { - // TODO is flush missing somewhere else? - // wait UART is writable again before return - timeout_tv = timeval_from_ms(1000 + result * 12500 / _baud); - select(_fd + 1, NULL, &writefds, NULL, &timeout_tv); - // done - break; - } - if (txbytes < size) - { - timeout_tv = timeval_from_ms(1000 + result * 12500 / _baud); - continue; - } - } - // This shouldn't happen, if r > 0 our fd has to be in the list! - Debug_println("UART write() unexpected select result"); - } - } - return txbytes; -} - -size_t UARTManager::write(const char *str) -{ - return write((const uint8_t *)str, strlen(str)); -} - -#endif // __linux__ || __APPLE__ - -#endif // !ESP_PLATFORM \ No newline at end of file diff --git a/lib/hardware/fnUARTWindows.cpp b/lib/hardware/fnUARTWindows.cpp deleted file mode 100644 index eb7fbdb33..000000000 --- a/lib/hardware/fnUARTWindows.cpp +++ /dev/null @@ -1,445 +0,0 @@ -#ifndef ESP_PLATFORM - -#if defined(_WIN32) - -// Windows UART code - -#include "fnUART.h" - -#include -#include -#include -#include -#include // write(), read(), close() -#include // Error integer and strerror() function -#include // Contains file controls like O_RDWR - -#include "compat_string.h" -#include "fnSystem.h" - -#include "../../include/debug.h" - -#define UART_DEFAULT_BAUD 19200 - - -// Constructor -// UARTManager::UARTManager(uart_port_t uart_num) : _uart_num(uart_num), _uart_q(NULL) {} -UARTManager::UARTManager() : - _initialized(false), - _fd(INVALID_HANDLE_VALUE), - _device{0}, - _baud(UART_DEFAULT_BAUD) -{}; - -void UARTManager::end() -{ - if (_fd != INVALID_HANDLE_VALUE) - { - CloseHandle(_fd); - _fd = INVALID_HANDLE_VALUE; - Debug_printf("### UART stopped ###\n"); - } - _initialized = false; -} - -bool UARTManager::poll(int ms) -{ - // TODO check serial port command link and input data - fnSystem.delay_microseconds(500); // TODO use ms parameter - return false; -} - -void UARTManager::set_port(const char *device, int command_pin, int proceed_pin) -{ - if (device != nullptr) - strlcpy(_device, device, sizeof(_device)); - - _command_pin = command_pin; - _proceed_pin = proceed_pin; - - switch (_command_pin) - { -// TODO move from fnConfig.h to fnUART.h -// enum serial_command_pin -// { -// SERIAL_COMMAND_NONE = 0, -// SERIAL_COMMAND_DSR, -// SERIAL_COMMAND_CTS, -// SERIAL_COMMAND_RI, -// SERIAL_COMMAND_INVALID -// }; - case 1: // SERIAL_COMMAND_DSR - _command_status = MS_DSR_ON; - break; - case 2: // SERIAL_COMMAND_CTS - _command_status = MS_CTS_ON; - break; - case 3: // SERIAL_COMMAND_RI - _command_status = MS_RING_ON; - break; - default: - _command_status = 0; - } - -// TODO move from fnConfig.h to fnUART.h -// enum serial_proceed_pin -// { -// SERIAL_PROCEED_NONE = 0, -// SERIAL_PROCEED_DTR, -// SERIAL_PROCEED_RTS, -// SERIAL_PROCEED_INVALID -// }; - switch (_proceed_pin) - { - case 1: // SERIAL_PROCEED_DTR - _proceed_set = SETDTR; - _proceed_clear = CLRDTR; - break; - case 2: // SERIAL_PROCEED_RTS - _proceed_set = SETRTS; - _proceed_clear = CLRRTS; - break; - default: - _proceed_set = 0; - _proceed_clear = 0; - } -} - -const char* UARTManager::get_port(int *ptr_command_pin, int *ptr_proceed_pin) -{ - if (ptr_command_pin) - *ptr_command_pin = _command_pin; - if (ptr_proceed_pin) - *ptr_proceed_pin = _proceed_pin; - return _device; -} - -void UARTManager::begin(int baud) -{ - if(_initialized) - { - end(); - } - - _errcount = 0; - _suspend_time = 0; - - // Open the serial port - if (*_device == 0) - { - Debug_println("Serial port is not configured!"); - suspend(); - return; - } - //wstring port_with_prefix = _prefix_port_if_needed(port_); - //LPCWSTR lp_port = port_with_prefix.c_str(); - Debug_printf("Setting up serial port %s\n", _device); - _fd = CreateFile(_device, - GENERIC_READ | GENERIC_WRITE, - 0, - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0); - - if (_fd == INVALID_HANDLE_VALUE) - { - DWORD err = GetLastError(); - Debug_printf("Failed to open serial port, error: %d\n", err); - if (err == ERROR_FILE_NOT_FOUND) - { - Debug_printf("Device not found\n"); - } - suspend(); - return; - } - - DCB dcbSerialParams = {0}; - dcbSerialParams.DCBlength=sizeof(dcbSerialParams); - - if (!GetCommState(_fd, &dcbSerialParams)) - { - //error getting state - Debug_printf("GetCommState error: %d\n", GetLastError()); - suspend(); - return; - } - - dcbSerialParams.ByteSize = 8; // 8 bits per byte - dcbSerialParams.StopBits = ONESTOPBIT; // one stop bit - dcbSerialParams.Parity = NOPARITY; // no parity - // no flowcontrol - dcbSerialParams.fOutxCtsFlow = false; - dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; - dcbSerialParams.fOutX = false; - dcbSerialParams.fInX = false; - - // activate settings - if (!SetCommState(_fd, &dcbSerialParams)){ - Debug_printf("SetCommState error: %d\n", GetLastError()); - suspend(); - return; - } - - Debug_printf("### UART initialized ###\n"); - // Set initialized. - _initialized=true; - set_baudrate(baud); -} - -void UARTManager::suspend(int sec) -{ - Debug_println("Suspending serial port"); - struct timeval tv; - gettimeofday(&tv, NULL); - _suspend_time = tv.tv_sec + sec; - end(); -} - -void UARTManager::flush_input() -{ - if (_initialized) - PurgeComm(_fd, PURGE_RXCLEAR); -} - -/* Clears input buffer and flushes out transmit buffer waiting at most - waiting MAX_FLUSH_WAIT_TICKS until all sends are completed -*/ -void UARTManager::flush() -{ - if (_initialized) - FlushFileBuffers(_fd); -} - -/* Returns number of bytes available in receive buffer or -1 on error -*/ -int UARTManager::available() -{ - if (!_initialized) - return 0; - - COMSTAT cs; - if (!ClearCommError(_fd, NULL, &cs)) - return 0; - return (size_t)cs.cbInQue; -} - -void UARTManager::set_baudrate(uint32_t baud) -{ - Debug_printf("UART set_baudrate: %d\n", baud); - - if (!_initialized) - return; - - if (baud == 0) - baud = 19200; - - int baud_id = 0; - - // map baud rate to predefined constant - switch (baud) - { -#ifdef CBR_300 - case 300: - baud_id = CBR_300; - break; -#endif -#ifdef CBR_600 - case 600: - baud_id = CBR_600; - break; -#endif -#ifdef CBR_1200 - case 1200: - baud_id = CBR_1200; - break; -#endif -#ifdef CBR_1800 - case 1800: - baud_id = CBR_1800; - break; -#endif -#ifdef CBR_2400 - case 2400: - baud_id = CBR_2400; - break; -#endif -#ifdef CBR_4800 - case 4800: - baud_id = CBR_4800; - break; -#endif -#ifdef CBR_9600 - case 9600: - baud_id = CBR_9600; - break; -#endif -#ifdef CBR_19200 - case 19200: - baud_id = CBR_19200; - break; -#endif -#ifdef CBR_38400 - case 38400: - baud_id = CBR_38400; - break; -#endif -#ifdef CBR_57600 - case 57600: - baud_id = CBR_57600; - break; -#endif -#ifdef CBR_115200 - case 115200: - baud_id = CBR_115200; - break; -#endif - default: - // no constant for given baud rate, try to blindly assign it - baud_id = baud; - } - - DCB dcbSerialParams = {0}; - dcbSerialParams.DCBlength=sizeof(dcbSerialParams); - - if (!GetCommState(_fd, &dcbSerialParams)) - { - //error getting state - Debug_printf("GetCommState error: %d\n", GetLastError()); - return; - } - - dcbSerialParams.BaudRate = baud_id; - - // activate settings - if (!SetCommState(_fd, &dcbSerialParams)){ - Debug_printf("SetCommState error: %d\n", GetLastError()); - return; - } - - // Setup timeouts - COMMTIMEOUTS timeouts = {0}; - timeouts.ReadIntervalTimeout = 50; - timeouts.ReadTotalTimeoutConstant = 500; - timeouts.ReadTotalTimeoutMultiplier = 50; - timeouts.WriteTotalTimeoutConstant = 500; - timeouts.WriteTotalTimeoutMultiplier = 50; - if (!SetCommTimeouts(_fd, &timeouts)) - { - Debug_printf("Error setting timeouts.\n"); - } - - _baud = baud; -} - -bool UARTManager::command_asserted(void) -{ - DWORD status; - - if (! _initialized) - { - // is serial port suspended ? - if (_suspend_time != 0) - { - struct timeval tv; - gettimeofday(&tv, NULL); - if (_suspend_time > tv.tv_sec) - return false; - // try to re-open serial port - begin(_baud); - } - if (! _initialized) - return false; - } - - if (!GetCommModemStatus(_fd, &status)) - { - // handle serial port errors - _errcount++; - if(_errcount == 1) - Debug_printf("UART command_asserted() GetCommModemStatus error: %d\n", GetLastError()); - else if (_errcount > 1000) - suspend(); - return false; - } - _errcount = 0; - - return ((status & _command_status) != 0); -} - -void UARTManager::set_proceed(bool level) -{ - static int last_level = -1; // 0,1 or -1 for unknown - int new_level = level ? 0 : 1; - int result; - - if (!_initialized) - return; - if (last_level == new_level) - return; - - Debug_print(level ? "+" : "-"); - last_level = new_level; - - if (level) { - EscapeCommFunction(_fd, _proceed_set); - } else { - EscapeCommFunction(_fd, _proceed_clear); - } -} - -timeval timeval_from_ms(const uint32_t millis) -{ - timeval tv; - tv.tv_sec = millis / 1000; - tv.tv_usec = (millis - (tv.tv_sec * 1000)) * 1000; - return tv; -} - -bool UARTManager::waitReadable(uint32_t timeout_ms) -{ - return false; -} - -int UARTManager::read(void) -{ - uint8_t byte; - return (readBytes(&byte, 1) == 1) ? byte : -1; -} - -size_t UARTManager::readBytes(uint8_t *buffer, size_t length) -{ - if (!_initialized) - return 0; - - DWORD rxbytes; - if (!ReadFile(_fd, buffer, (DWORD)length, &rxbytes, NULL)) - { - Debug_printf("UART readBytes() read error: %d\n", GetLastError()); - } - return (size_t)(rxbytes); -} - -size_t UARTManager::write(uint8_t c) -{ - return write(&c, 1); -} - -size_t UARTManager::write(const uint8_t *buffer, size_t size) -{ - DWORD txbytes; - if (!WriteFile(_fd, buffer, (DWORD)size, &txbytes, NULL)) - { - Debug_printf("UART write() write error: %dn", GetLastError()); - } - return (size_t)txbytes; -} - -size_t UARTManager::write(const char *str) -{ - return write((const uint8_t *)str, strlen(str)); -} - -#endif // _WIN32 - -#endif // !ESP_PLATFORM \ No newline at end of file diff --git a/lib/http/httpServiceConfigurator.cpp b/lib/http/httpServiceConfigurator.cpp index 2e196c8ea..28513ffe9 100644 --- a/lib/http/httpServiceConfigurator.cpp +++ b/lib/http/httpServiceConfigurator.cpp @@ -615,10 +615,8 @@ void fnHttpServiceConfigurator::config_boip(std::string enable_boip, std::string // Update settings (on ESP reboot is needed) #ifndef ESP_PLATFORM -#if defined(BUILD_ATARI) - SYSTEM_BUS.set_netsio_host(Config.get_boip_host().c_str(), Config.get_boip_port()); -#elif defined(BUILD_COCO) - fnDwCom.set_becker_host(Config.get_boip_host().c_str(), Config.get_boip_port()); +#if defined(BUILD_ATARI) || defined(BUILD_COCO) + SYSTEM_BUS.setHost(Config.get_boip_host().c_str(), Config.get_boip_port()); #endif #endif @@ -629,10 +627,8 @@ void fnHttpServiceConfigurator::config_boip(std::string enable_boip, std::string // Apply settings (on ESP reboot is needed) #ifndef ESP_PLATFORM -#if defined(BUILD_ATARI) - SYSTEM_BUS.reset_sio_port(Config.get_boip_enabled() ? SioCom::sio_mode::NETSIO : SioCom::sio_mode::SERIAL); -#elif defined(BUILD_COCO) - fnDwCom.reset_drivewire_port(Config.get_boip_enabled() ? DwCom::dw_mode::BECKER : DwCom::dw_mode::SERIAL); +#if defined(BUILD_ATARI) || defined(BUILD_COCO) + SYSTEM_BUS.selectSerialPort(Config.get_boip_enabled() == 0); #endif #endif diff --git a/lib/http/httpServiceParser.cpp b/lib/http/httpServiceParser.cpp index fd8750f66..56526de1c 100644 --- a/lib/http/httpServiceParser.cpp +++ b/lib/http/httpServiceParser.cpp @@ -384,7 +384,7 @@ const string fnHttpServiceParser::substitute_tag(const string &tag) #ifndef ESP_PLATFORM case FN_SIO_HSTEXT: hsioindex = SYSTEM_BUS.getHighSpeedIndex(); - if (hsioindex == HSIO_DISABLED_INDEX) + if (hsioindex == HSIO_INVALID_INDEX) resultstream << "HSIO Disabled"; else resultstream << hsioindex; @@ -395,6 +395,7 @@ const string fnHttpServiceParser::substitute_tag(const string &tag) break; #endif /* BUILD_ATARI */ #if defined(BUILD_RS232) +#warning "Why isn't this using Config.get_serial_baud() below?" case FN_SERIAL_PORT_BAUD: resultstream << Config.get_rs232_baud(); break; diff --git a/lib/runcpm/abstraction_fujinet.h b/lib/runcpm/abstraction_fujinet.h index f98e50033..d6d0c56b9 100644 --- a/lib/runcpm/abstraction_fujinet.h +++ b/lib/runcpm/abstraction_fujinet.h @@ -17,7 +17,7 @@ #include "fnWiFi.h" #include "fnFsSD.h" #ifdef ESP_PLATFORM -#include "fnUART.h" +#include "IOChannel.h" #endif #include "fnTcpServer.h" #include "fnTcpClient.h" diff --git a/lib/runcpm/abstraction_fujinet_apple2.h b/lib/runcpm/abstraction_fujinet_apple2.h index 09486887e..8cc1abe39 100644 --- a/lib/runcpm/abstraction_fujinet_apple2.h +++ b/lib/runcpm/abstraction_fujinet_apple2.h @@ -17,7 +17,6 @@ #include "fnSystem.h" #include "fnWiFi.h" #include "fnFsSD.h" -#include "fnUART.h" #include "fnTcpServer.h" #include "fnTcpClient.h" diff --git a/src/main.cpp b/src/main.cpp index f3344edc2..56f6d35f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -150,7 +150,7 @@ void main_setup(int argc, char *argv[]) //You can change the baud rate and pin numbers similar to Serial.begin() here. console.begin(DEBUG_SPEED); #else - Serial.begin(DEBUG_SPEED); + Serial.begin(ChannelConfig().baud(DEBUG_SPEED).deviceID(FN_UART_DEBUG)); #endif #ifdef DEBUG