Render bridge (live_bridge.py, vrview_gl.py): - Hat glances render (left/right frame the canopy, hat-down = clean rear). Root bug was a stale _ckpt['fix'] key -> KeyError every glance frame -> render aborted (screen froze on hold, snapped back on release). The glance itself is the authentic eye-DCS action-0x1f reflush fp_cam already applies. - Torso twist turret-true (root-axis yaw, zero parallax); lasers follow torso. - Rear glance drops the canopy shell for a clean view (original-hardware behavior); mission-fade shroud 9fd hidden. - Wireframe debug mode (VRVIEW_WIREFRAME / 'w' key), scene-pass scoped. - Renderer output = 832x512, the dPL3 board's native framebuffer res. DOSBox-X fork: namedpipe serial backend (serialnamedpipe.cpp/.h) for vRIO/vPLASMA, replacing com0com; overlapped non-blocking I/O; typed frames (0x00 data / 0x01 DTR+RTS). Tracked copies + apply steps in vpx-device. Docs: COCKPIT-CAGE-NOTES (full glance/twist/rear forensics), XP-PORT-PLAN (back-burnered), RIO-NOTES (namedpipe + keypad), pipe/egg conf variants. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
96 lines
3.4 KiB
C++
96 lines
3.4 KiB
C++
/*
|
|
* 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 <len:u8> <bytes> serial data, len >= 1 (batching allowed)
|
|
* 0x01 <lines:u8> 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:<name> maps to \\.\pipe\<name>; 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 <windows.h>
|
|
|
|
#include <deque>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
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<uint8_t> txq; // bytes waiting for the next write
|
|
std::vector<uint8_t> tx_pend; // buffer owned by the in-flight write
|
|
|
|
std::vector<uint8_t> inbuf; // partial frame reassembly
|
|
std::deque<uint8_t> 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
|