/* * VWE fork: serial-over-named-pipe backend (Windows only). * * Replaces com0com virtual COM pairs for the vRIO cockpit board and the * vPLASMA score display: DOSBox is the pipe CLIENT with background retry; * the peripheral app (vRIO / vPLASMA) is the pipe SERVER. An unconnected * pipe behaves like an unplugged cable: the UART exists, modem-in lines * (CTS/DSR/CD) are low, writes are discarded. * * Wire format (single duplex byte-mode pipe, typed frames, identical in * both directions -- contract pinned with the vRIO session 2026-07-12): * 0x00 serial data, len >= 1 (batching allowed) * 0x01 sender's own OUTPUT lines: bit0 DTR, bit1 RTS; * the receiver applies the null-modem cross * (their DTR -> our DSR+CD, their RTS -> our CTS) * On connect each side sends one 0x01 with its current state. An unknown * frame type is a protocol bug: log + drop the connection, no resync. * * Conf: serial1=namedpipe pipe:vrio [rxpollus:100] [rxburst:16] [rxdelay:n] * (pipe: maps to \\.\pipe\; a full \\... path also works; * rx options have directserial semantics) */ #ifndef DOSBOX_SERIALNAMEDPIPE_H #define DOSBOX_SERIALNAMEDPIPE_H #include "dosbox.h" #if defined(WIN32) #include "serialport.h" #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #include class CSerialNamedPipe : public CSerial { public: CSerialNamedPipe(Bitu id, CommandLine* cmd); virtual ~CSerialNamedPipe(); void updatePortConfig(uint16_t divider, uint8_t lcr); void updateMSR(); void transmitByte(uint8_t val, bool first); void setBreak(bool value); void setRTSDTR(bool rts, bool dtr); void setRTS(bool val); void setDTR(bool val); void handleUpperEvent(uint16_t type); private: void tryConnect(); void dropConnection(const char* why); void pumpPipe(); // drain pipe -> parse frames -> rxq / line state bool doReceive(); // deliver one rx byte to the UART if available void queueSend(const uint8_t* data, DWORD len); // NEVER blocks void kickTx(); // start the next overlapped write if idle void pollTx(); // reap a completed / wedged overlapped write void sendLineState(); // frame 0x01 with our current DTR/RTS HANDLE pipe = INVALID_HANDLE_VALUE; std::string pipename; double next_retry_ms = 0.0; // PIC_FullIndex() of the next connect attempt // ALL pipe I/O is overlapped: a blocking write here deadlocked the emu // thread against a peer that also writes-first (both hellos, no reader). OVERLAPPED tx_ov = {}; OVERLAPPED rx_ov = {}; bool tx_inflight = false; double tx_wedge_ms = 0.0; // deadline for an unfinished write std::vector txq; // bytes waiting for the next write std::vector tx_pend; // buffer owned by the in-flight write std::vector inbuf; // partial frame reassembly std::deque rxq; // decoded serial bytes awaiting the UART bool cur_dtr = false; // our output lines (mirrors MCR writes) bool cur_rts = false; // receive pacing, directserial semantics (VWE RIO low-latency knobs) float rx_poll_ms = 1.0f; float rx_burst_div = 1.0f; Bitu rx_retry = 0; Bitu rx_retry_max = 0; Bitu rx_state = 0; }; #endif // WIN32 #endif // DOSBOX_SERIALNAMEDPIPE_H