From 566ce1b7f80066d92e1873ad091ef221ccb11d9d Mon Sep 17 00:00:00 2001 From: Asbelos Date: Tue, 14 Nov 2023 19:41:05 +0000 Subject: [PATCH] Virtual LCD phase 1 --- CommandDistributor.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++ CommandDistributor.h | 9 +++++++- DCCEXParser.cpp | 6 +++++- StringFormatter.cpp | 17 +++++++++++++++ StringFormatter.h | 1 - 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/CommandDistributor.cpp b/CommandDistributor.cpp index 351a18d..788e4e6 100644 --- a/CommandDistributor.cpp +++ b/CommandDistributor.cpp @@ -105,6 +105,7 @@ void CommandDistributor::parse(byte clientId,byte * buffer, RingStream * stream void CommandDistributor::forget(byte clientId) { if (clients[clientId]==WITHROTTLE_TYPE) WiThrottle::forget(clientId); clients[clientId]=NONE_TYPE; + if (virtualLCDClient==clientId) virtualLCDClient=RingStream::NO_CLIENT; } #endif @@ -280,3 +281,51 @@ void CommandDistributor::broadcastRouteState(uint16_t routeId, byte state ) { void CommandDistributor::broadcastRouteCaption(uint16_t routeId, const FSH* caption ) { broadcastReply(COMMAND_TYPE, F("\n"),routeId,caption); } + +Print * CommandDistributor::getVirtualLCDSerial(byte screen, byte row) { + Print * stream=virtualLCDSerial; + #ifdef CD_HANDLE_RING + rememberVLCDClient=RingStream::NO_CLIENT; + if (!stream && virtualLCDClient!=RingStream::NO_CLIENT) { + // If we are broadcasting from a wifi/eth process we need to complete its output + // before merging broadcasts in the ring, then reinstate it in case + // the process continues to output to its client. + if ((rememberVLCDClient = ring->peekTargetMark()) != RingStream::NO_CLIENT) { + ring->commit(); + } + ring->mark(virtualLCDClient); + stream=ring; + } + #endif + if (stream) StringFormatter::send(stream,F("<@ %d %d \""), screen,row); + return stream; +} + +void CommandDistributor::commitVirtualLCDSerial() { + #ifdef CD_HANDLE_RING + if (virtualLCDClient!=RingStream::NO_CLIENT) { + StringFormatter::send(ring,F("\">\n")); + ring->commit(); + if (rememberVLCDClient!=RingStream::NO_CLIENT) ring->mark(rememberVLCDClient); + return; + } + #endif + StringFormatter::send(virtualLCDSerial,F("\">\n")); +} + +void CommandDistributor::setVirtualLCDSerial(Print * stream) { + #ifdef CD_HANDLE_RING + virtualLCDClient=RingStream::NO_CLIENT; + if (stream && stream->availableForWrite()==RingStream::THIS_IS_A_RINGSTREAM) { + virtualLCDClient=((RingStream *) stream)->peekTargetMark(); + virtualLCDSerial=nullptr; + return; + } + #endif + virtualLCDSerial=stream; +} + +Print* CommandDistributor::virtualLCDSerial=nullptr; +byte CommandDistributor::virtualLCDClient=0xFF; +byte CommandDistributor::rememberVLCDClient=0; + diff --git a/CommandDistributor.h b/CommandDistributor.h index 83bfbbd..359c0fe 100644 --- a/CommandDistributor.h +++ b/CommandDistributor.h @@ -60,8 +60,15 @@ public : static void forget(byte clientId); static void broadcastRouteState(uint16_t routeId,byte state); static void broadcastRouteCaption(uint16_t routeId,const FSH * caption); - + // Handling code for virtual LCD receiver. + static Print * getVirtualLCDSerial(byte screen, byte row); + static void commitVirtualLCDSerial(); + static void setVirtualLCDSerial(Print * stream); + private: + static Print * virtualLCDSerial; + static byte virtualLCDClient; + static byte rememberVLCDClient; }; #endif diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 96596c6..369d941 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -724,7 +724,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) return; break; #endif - case '=': // TACK MANAGER CONTROL <= [params]> + case '=': // TRACK MANAGER CONTROL <= [params]> if (TrackManager::parseJ(stream, params, p)) return; break; @@ -897,6 +897,10 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) case 'L': // LCC interface implemented in EXRAIL parser break; // Will if not intercepted by EXRAIL + case '@': // JMRI saying "give me virtual LCD msgs" + CommandDistributor::setVirtualLCDSerial(stream); + return; + default: //anything else will diagnose and drop out to DIAG(F("Opcode=%c params=%d"), opcode, params); for (int i = 0; i < params; i++) diff --git a/StringFormatter.cpp b/StringFormatter.cpp index b40de1c..218e617 100644 --- a/StringFormatter.cpp +++ b/StringFormatter.cpp @@ -19,6 +19,7 @@ #include "StringFormatter.h" #include #include "DisplayInterface.h" +#include "CommandDistributor.h" bool Diag::ACK=false; bool Diag::CMD=false; @@ -45,6 +46,14 @@ void StringFormatter::lcd(byte row, const FSH* input...) { send2(&USB_SERIAL,input,args); send(&USB_SERIAL,F(" *>\n")); + // send to virtual LCD collector (if any) + Print * virtualLCD=CommandDistributor::getVirtualLCDSerial(0,row); + if (virtualLCD) { + va_start(args, input); + send2(virtualLCD,input,args); + CommandDistributor::commitVirtualLCDSerial(); + } + DisplayInterface::setRow(row); va_start(args, input); send2(DisplayInterface::getDisplayHandler(),input,args); @@ -52,6 +61,14 @@ void StringFormatter::lcd(byte row, const FSH* input...) { void StringFormatter::lcd2(uint8_t display, byte row, const FSH* input...) { va_list args; + + // send to virtual LCD collector (if any) + Print * virtualLCD=CommandDistributor::getVirtualLCDSerial(display,row); + if (virtualLCD) { + va_start(args, input); + send2(virtualLCD,input,args); + CommandDistributor::commitVirtualLCDSerial(); + } DisplayInterface::setRow(display, row); va_start(args, input); diff --git a/StringFormatter.h b/StringFormatter.h index 1231d54..25d15e2 100644 --- a/StringFormatter.h +++ b/StringFormatter.h @@ -54,6 +54,5 @@ class StringFormatter private: static void send2(Print * serial, const FSH* input,va_list args); static void printPadded(Print* stream, long value, byte width, bool formatLeft); - }; #endif