From dfa798c14938069261a3c6903a63bfe86f219b69 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Thu, 2 Nov 2023 09:12:31 -0400 Subject: [PATCH 01/32] seems to work now --- Wifi_NINA.cpp | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 8d54030..fdf496a 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -55,7 +55,7 @@ public: NetworkClient(WiFiClient c) { wifi = c; }; - bool ok() { + bool ok() { return (inUse && wifi.connected()); }; bool recycle(WiFiClient c) { @@ -65,13 +65,13 @@ public: // return false here until we have // implemented a LRU timer // if (LRU too recent) return false; - return false; + //return false; wifi = c; inUse = true; return true; }; - WiFiClient wifi; + WiFiClient wifi; bool inUse = true; }; @@ -248,6 +248,9 @@ bool WifiNINA::setup(const char *SSid, // #else DIAG(F("Server will be started on port %d"),port); // #endif + ip = WiFi.localIP(); + LCD(4,F("IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + LCD(5,F("Port:%d"), port); return true; } @@ -271,31 +274,33 @@ void WifiNINA::loop() { for (clientId=0; clientIdavailable()) { - WiFiClient client; - while (client = server->available()) { + WiFiClient client = server->available(); + if (client) { + ///while (!client) { for (clientId=0; clientId=clients.size()) { - NetworkClient nc(client); - clients.push_back(nc); + auto nc=new NetworkClient(client); + clients.push_back(*nc); + delete nc; ip = client.remoteIP(); - DIAG(F("New client %d, %s"), clientId, ip); + DIAG(F("New client %d, %d.%d.%d.%d"), clientId, ip[0], ip[1], ip[2], ip[3]); } - } + ///} } // loop over all connected clients for (clientId=0; clientId Date: Thu, 2 Nov 2023 14:00:02 -0400 Subject: [PATCH 02/32] keeping up to date - cleaning --- Wifi_NINA.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index fdf496a..bd32bef 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -284,8 +284,8 @@ void WifiNINA::loop() { } } WiFiClient client = server->available(); - if (client) { - ///while (!client) { + if (client == true) { + ///while (client.available() == true) { for (clientId=0; clientId=clients.size()) { - auto nc=new NetworkClient(client); + NetworkClient* nc=new NetworkClient(client); clients.push_back(*nc); - delete nc; + //delete nc; ip = client.remoteIP(); DIAG(F("New client %d, %d.%d.%d.%d"), clientId, ip[0], ip[1], ip[2], ip[3]); } From b1f5c34ef222f5223c66dc4f16c9359bfab254fd Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 3 Nov 2023 07:17:17 -0400 Subject: [PATCH 03/32] compiles, but crashes on client connect --- Wifi_NINA.cpp | 79 ++++++++++++++++++++++++++++++++++++++++++++++++--- Wifi_NINA.h | 6 +++- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index bd32bef..38bed4f 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -49,7 +49,7 @@ #else #warning "WiFiNINA has no SPI port or pin allocations for this archiecture yet!" #endif - +#define MAX_CLIENTS 10 class NetworkClient { public: NetworkClient(WiFiClient c) { @@ -75,7 +75,7 @@ public: bool inUse = true; }; -static std::vector clients; // a list to hold all clients +//static std::vector clients; // a list to hold all clients static WiFiServer *server = NULL; static RingStream *outboundRing = new RingStream(10240); static bool APmode = false; @@ -264,7 +264,7 @@ const char *wlerror[] = { "WL_DISCONNECTED" }; -void WifiNINA::loop() { +/*void WifiNINA::loop() { int clientId; //tmp loop var // really no good way to check for LISTEN especially in AP mode? @@ -284,7 +284,7 @@ void WifiNINA::loop() { } } WiFiClient client = server->available(); - if (client == true) { + if (client) { ///while (client.available() == true) { for (clientId=0; clientIdavailable(); + if (!newClient) return; + for (byte clientId=0; clientIdconnected()) { + DIAG(F("Remove client %d"), clientId); + CommandDistributor::forget(clientId); + delete c; // we have now finished with this client + clients[clientId]=nullptr; + } + } +} + +void WifiNINA::checkForClientInput() { + // Find a client providing input + for (byte clientId=0; clientIdavailable(); + if (len) { + // read data from client + byte cmd[len+1]; + for(int i=0; iread(); + cmd[len]=0; + CommandDistributor::parse(clientId,cmd,outboundRing); + } + } + } +} +void WifiNINA::checkForClientOutput() { + // something to write out? + auto clientId=outboundRing->read(); + if (clientId < 0) return; + auto replySize=outboundRing->count(); + if (replySize==0) return; // nothing to send + + auto c=clients[clientId]; + if (!c) { + // client is gone, throw away msg + for (int i=0;iread(); + return; + } + + // emit data to the client object + // This should work in theory, the + for (int i=0;iwrite(outboundRing->read()); + +} + +void WifiNINA::loop() { + checkForLostClients(); + checkForNewClient(); + checkForClientInput(); + WiThrottle::loop(outboundRing); // allow withrottle to broadcast if needed + checkForClientOutput(); +} + #endif // WIFI_NINA \ No newline at end of file diff --git a/Wifi_NINA.h b/Wifi_NINA.h index f841b4f..2cf5fbd 100644 --- a/Wifi_NINA.h +++ b/Wifi_NINA.h @@ -35,8 +35,12 @@ public: const char *hostname, const int port, const byte channel, - const bool forceAP); + const bool forceAP); static void loop(); private: + static void checkForNewClient(); + static void checkForLostClients(); + static void checkForClientInput(); + static void checkForClientOutput(); }; #endif //WifiNINA_h From 05db1bdd9082f2f3bf02257a95c5bdc4e5d463cd Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 3 Nov 2023 07:34:05 -0400 Subject: [PATCH 04/32] cleaning --- Wifi_NINA.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 38bed4f..c662e13 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -21,7 +21,7 @@ #include "defines.h" #ifdef WIFI_NINA -#include +//#include #include #ifndef ARDUINO_GIGA #include @@ -49,8 +49,8 @@ #else #warning "WiFiNINA has no SPI port or pin allocations for this archiecture yet!" #endif -#define MAX_CLIENTS 10 -class NetworkClient { +#define MAX_CLIENTS 4 +/*class NetworkClient { public: NetworkClient(WiFiClient c) { wifi = c; @@ -73,7 +73,7 @@ public: }; WiFiClient wifi; bool inUse = true; -}; +};*/ //static std::vector clients; // a list to hold all clients static WiFiServer *server = NULL; From d95d9c193e108c26f39f4ba0edfe0fb8e827aa65 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 3 Nov 2023 07:48:12 -0400 Subject: [PATCH 05/32] allows client, but immidiatly drops client --- Wifi_NINA.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index c662e13..19efc14 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -378,7 +378,7 @@ void WifiNINA::checkForNewClient() { for (byte clientId=0; clientIdconnected()) { DIAG(F("Remove client %d"), clientId); CommandDistributor::forget(clientId); - delete c; // we have now finished with this client + //delete c; // we have now finished with this client clients[clientId]=nullptr; } } From b632088b19c90d4fd0f8713337b777d83f762c13 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 3 Nov 2023 09:06:42 -0400 Subject: [PATCH 06/32] cleaning... --- Wifi_NINA.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 19efc14..1ae888b 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -390,7 +390,7 @@ void WifiNINA::checkForLostClients() { if(c && !c->connected()) { DIAG(F("Remove client %d"), clientId); CommandDistributor::forget(clientId); - //delete c; // we have now finished with this client + //delete c; // this causes a crash when client drops.. commenting out for now clients[clientId]=nullptr; } } @@ -412,24 +412,22 @@ void WifiNINA::checkForClientInput() { } } } + void WifiNINA::checkForClientOutput() { // something to write out? auto clientId=outboundRing->read(); if (clientId < 0) return; auto replySize=outboundRing->count(); if (replySize==0) return; // nothing to send - auto c=clients[clientId]; if (!c) { // client is gone, throw away msg for (int i=0;iread(); return; } - // emit data to the client object // This should work in theory, the for (int i=0;iwrite(outboundRing->read()); - } void WifiNINA::loop() { From 741771c4fe47d0097435a4bda6ecffa6940cd5b3 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 3 Nov 2023 11:49:25 -0400 Subject: [PATCH 07/32] added diags for debug tracking... --- Wifi_NINA.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 1ae888b..ba57f00 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -378,7 +378,7 @@ void WifiNINA::checkForNewClient() { for (byte clientId=0; clientIdconnected()) { DIAG(F("Remove client %d"), clientId); CommandDistributor::forget(clientId); - //delete c; // this causes a crash when client drops.. commenting out for now + //delete c; //TJF: this causes a crash when client drops.. commenting out for now. clients[clientId]=nullptr; } } @@ -423,10 +423,14 @@ void WifiNINA::checkForClientOutput() { if (!c) { // client is gone, throw away msg for (int i=0;iread(); + DIAG(F("gone, drop message.")); //TJF: only for diag return; } // emit data to the client object // This should work in theory, the + DIAG(F("send message")); //TJF: only for diag + //TJF: the old code had to add a 0x00 byte to the end to terminate the + //TJF: c string, before sending it. i take it this is not needed? for (int i=0;iwrite(outboundRing->read()); } From 050fed6e9af26988da9d57d554e4c432496c3ed3 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 3 Nov 2023 13:40:48 -0400 Subject: [PATCH 08/32] crashes --- Wifi_NINA.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index ba57f00..46acfd4 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -184,7 +184,7 @@ bool WifiNINA::setup(const char *SSid, strMac += String(mac[i], HEX); } - DIAG(F("MAC address: %x:%x:%x:%x:%X;%x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + DIAG(F("MAC address: %x:%x:%x:%x:%x:%x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); strMac.remove(0,9); strMac.replace(":",""); @@ -200,7 +200,7 @@ bool WifiNINA::setup(const char *SSid, channel) == WL_AP_LISTENING) { DIAG(F("Wifi AP SSID %s PASS %s"),strSSID.c_str(),havePassword ? password : strPass.c_str()); ip = WiFi.localIP(); - DIAG(F("Wifi AP IP %s"),ip); + DIAG(F("Wifi AP IP %d.%d.%d.%d"),ip[0], ip[1], ip[2], ip[3]); wifiUp = true; APmode = true; } else { @@ -370,14 +370,14 @@ const char *wlerror[] = { } }*/ -WiFiClient * clients[MAX_CLIENTS]; // nulled in setup +WiFiClient clients[MAX_CLIENTS]; // nulled in setup void WifiNINA::checkForNewClient() { auto newClient=server->available(); if (!newClient) return; for (byte clientId=0; clientIdconnected()) { - DIAG(F("Remove client %d"), clientId); - CommandDistributor::forget(clientId); - //delete c; //TJF: this causes a crash when client drops.. commenting out for now. - clients[clientId]=nullptr; - } + if(c && !c.connected()) { + DIAG(F("Remove client %d"), clientId); + CommandDistributor::forget(clientId); + //delete c; //TJF: this causes a crash when client drops.. commenting out for now. + //clients[clientId]=NULL; // TJF: what to do... what to do... + } } } @@ -401,11 +401,11 @@ void WifiNINA::checkForClientInput() { for (byte clientId=0; clientIdavailable(); + auto len=c.available(); if (len) { // read data from client byte cmd[len+1]; - for(int i=0; iread(); + for(int i=0; iwrite(outboundRing->read()); + for (int i=0;iread()); } void WifiNINA::loop() { From 8a813c2a1ecdc1eb40965dc4853d78bc9068a642 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 3 Nov 2023 14:11:55 -0400 Subject: [PATCH 09/32] updating current, still crashes --- Wifi_NINA.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 46acfd4..5f8048d 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -149,7 +149,7 @@ bool WifiNINA::setup(const char *SSid, } if (WiFi.status() == WL_CONNECTED) { // String ip_str = sprintf("%xl", WiFi.localIP()); - DIAG(F("Wifi STA IP %d.%d.%d.%d"), WiFi.localIP()[0], WiFi.localIP()[1],WiFi.localIP()[2],WiFi.localIP()[3],WiFi.localIP()[4],WiFi.localIP()[5]); + DIAG(F("Wifi STA IP %d.%d.%d.%d"), WiFi.localIP()[0], WiFi.localIP()[1],WiFi.localIP()[2],WiFi.localIP()[3]); wifiUp = true; } else { DIAG(F("Could not connect to Wifi SSID %s"),SSid); @@ -164,7 +164,7 @@ bool WifiNINA::setup(const char *SSid, } if (WiFi.status() == WL_CONNECTED) { ip = WiFi.localIP(); - DIAG(F("Wifi STA IP 2nd try %s"), ip); + DIAG(F("Wifi STA IP 2nd try %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); wifiUp = true; } else { DIAG(F("Wifi STA mode FAIL. Will revert to AP mode")); @@ -435,9 +435,9 @@ void WifiNINA::checkForClientOutput() { } void WifiNINA::loop() { - checkForLostClients(); + checkForLostClients(); // *** checkForNewClient(); - checkForClientInput(); + checkForClientInput(); // *** WiThrottle::loop(outboundRing); // allow withrottle to broadcast if needed checkForClientOutput(); } From e6797d1095a9ee7ee3344277187e6f56e9ce53ab Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Sat, 4 Nov 2023 07:36:23 -0400 Subject: [PATCH 10/32] Giga wifi works for 3 clients MAX --- Wifi_NINA.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 5f8048d..ea970f3 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -49,7 +49,7 @@ #else #warning "WiFiNINA has no SPI port or pin allocations for this archiecture yet!" #endif -#define MAX_CLIENTS 4 +#define MAX_CLIENTS 10 /*class NetworkClient { public: NetworkClient(WiFiClient c) { @@ -80,7 +80,6 @@ static WiFiServer *server = NULL; static RingStream *outboundRing = new RingStream(10240); static bool APmode = false; static IPAddress ip; - // #ifdef WIFI_TASK_ON_CORE0 // void wifiLoop(void *){ // for(;;){ @@ -370,14 +369,14 @@ const char *wlerror[] = { } }*/ -WiFiClient clients[MAX_CLIENTS]; // nulled in setup +WiFiClient * clients[MAX_CLIENTS]; // nulled in setup void WifiNINA::checkForNewClient() { auto newClient=server->available(); if (!newClient) return; for (byte clientId=0; clientIdconnected()) { + clients[clientId]->stop(); DIAG(F("Remove client %d"), clientId); CommandDistributor::forget(clientId); //delete c; //TJF: this causes a crash when client drops.. commenting out for now. - //clients[clientId]=NULL; // TJF: what to do... what to do... + clients[clientId]=nullptr; // TJF: what to do... what to do... } } } @@ -401,11 +401,11 @@ void WifiNINA::checkForClientInput() { for (byte clientId=0; clientIdavailable(); if (len) { // read data from client byte cmd[len+1]; - for(int i=0; iread(); cmd[len]=0; CommandDistributor::parse(clientId,cmd,outboundRing); } @@ -431,7 +431,7 @@ void WifiNINA::checkForClientOutput() { DIAG(F("send message")); //TJF: only for diag //TJF: the old code had to add a 0x00 byte to the end to terminate the //TJF: c string, before sending it. i take it this is not needed? - for (int i=0;iread()); + for (int i=0;iwrite(outboundRing->read()); } void WifiNINA::loop() { From 4430e9acdc51647be68a955fcd607ad1d86d9a7d Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Mon, 6 Nov 2023 09:46:58 -0500 Subject: [PATCH 11/32] committing to save, see pull comment --- Wifi_NINA.cpp | 194 +++++--------------------------------------------- 1 file changed, 19 insertions(+), 175 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index ea970f3..9664d84 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -2,7 +2,9 @@ © 2023 Paul M. Antoine © 2021 Harald Barth © 2023 Nathan Kellenicki - + © 2023 Travis Farmer + © 2023 Chris Harlow + This file is part of CommandStation-EX This is free software: you can redistribute it and/or modify @@ -20,20 +22,19 @@ */ #include "defines.h" -#ifdef WIFI_NINA +#ifdef WIFI_NINA || GIGA_WIFI //#include #include #ifndef ARDUINO_GIGA #include #else +#if defined(GIGA_WIFI) #include +#else +#include +#endif #endif #include "Wifi_NINA.h" -// #include "ESPmDNS.h" -// #include -// #include "esp_wifi.h" -// #include "WifiESP32.h" -// #include #include "DIAG.h" #include "RingStream.h" #include "CommandDistributor.h" @@ -46,47 +47,21 @@ #define ESP32_RESETN PA10 // Reset pin #define SPIWIFI_ACK PB3 // a.k.a BUSY or READY pin #define ESP32_GPIO0 -1 +#elif defined(ARDUINO_GIGA) + #define SPIWIFI SPI + #define SPIWIFI_SS 10 // Chip select pin + #define SPIWIFI_ACK 7 // a.k.a BUSY or READY pin + #define ESP32_RESETN 5 // Reset pin + #define ESP32_GPIO0 -1 // Not connected #else #warning "WiFiNINA has no SPI port or pin allocations for this archiecture yet!" #endif #define MAX_CLIENTS 10 -/*class NetworkClient { -public: - NetworkClient(WiFiClient c) { - wifi = c; - }; - bool ok() { - return (inUse && wifi.connected()); - }; - bool recycle(WiFiClient c) { - if (inUse == true) return false; - - // return false here until we have - // implemented a LRU timer - // if (LRU too recent) return false; - //return false; - - wifi = c; - inUse = true; - return true; - }; - WiFiClient wifi; - bool inUse = true; -};*/ - -//static std::vector clients; // a list to hold all clients static WiFiServer *server = NULL; static RingStream *outboundRing = new RingStream(10240); static bool APmode = false; static IPAddress ip; -// #ifdef WIFI_TASK_ON_CORE0 -// void wifiLoop(void *){ -// for(;;){ -// WifiNINA::loop(); -// } -// } -// #endif char asciitolower(char in) { if (in <= 'Z' && in >= 'A') @@ -106,7 +81,7 @@ bool WifiNINA::setup(const char *SSid, uint8_t tries = 40; // Set up the pins! -#ifndef ARDUINO_GIGA +#ifndef GIGA_WIFI WiFi.setPins(SPIWIFI_SS, SPIWIFI_ACK, ESP32_RESETN, ESP32_GPIO0, &SPIWIFI); #endif // check for the WiFi module: @@ -120,14 +95,6 @@ bool WifiNINA::setup(const char *SSid, String fv = WiFi.firmwareVersion(); DIAG(F("WifiNINA Firmware version found:%s"), fv.c_str()); - // clean start - // WiFi.mode(WIFI_STA); - // WiFi.disconnect(true); - // differnet settings that did not improve for haba - // WiFi.useStaticBuffers(true); - // WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); - // WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SECURITY); - const char *yourNetwork = "Your network "; if (strncmp(yourNetwork, SSid, 13) == 0 || strncmp("", SSid, 13) == 0) haveSSID = false; @@ -189,7 +156,7 @@ bool WifiNINA::setup(const char *SSid, strMac.replace(":",""); strMac.replace(":",""); // convert mac addr hex chars to lower case to be compatible with AT software - std::transform(strMac.begin(), strMac.end(), strMac.begin(), asciitolower); + //std::transform(strMac.begin(), strMac.end(), strMac.begin(), asciitolower); ///TJF: why does this fail compile with WiFiNINA, but not giga WiFi??? strSSID.concat(strMac); strPass.concat(strMac); } @@ -227,26 +194,8 @@ bool WifiNINA::setup(const char *SSid, server->begin(); // server started here -// #ifdef WIFI_TASK_ON_CORE0 -// //start loop task -// if (pdPASS != xTaskCreatePinnedToCore( -// wifiLoop, /* Task function. */ -// "wifiLoop",/* name of task. */ -// 10000, /* Stack size of task */ -// NULL, /* parameter of the task */ -// 1, /* priority of the task */ -// NULL, /* Task handle to keep track of created task */ -// 0)) { /* pin task to core 0 */ -// DIAG(F("Could not create wifiLoop task")); -// return false; -// } - -// // report server started after wifiLoop creation -// // when everything looks good -// DIAG(F("Server starting (core 0) port %d"),port); -// #else DIAG(F("Server will be started on port %d"),port); -// #endif + ip = WiFi.localIP(); LCD(4,F("IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); LCD(5,F("Port:%d"), port); @@ -263,112 +212,6 @@ const char *wlerror[] = { "WL_DISCONNECTED" }; -/*void WifiNINA::loop() { - int clientId; //tmp loop var - - // really no good way to check for LISTEN especially in AP mode? - wl_status_t wlStatus; - if (APmode || (wlStatus = (wl_status_t)WiFi.status()) == WL_CONNECTED) { - // loop over all clients and remove inactive - for (clientId=0; clientIdavailable(); - if (client) { - ///while (client.available() == true) { - for (clientId=0; clientId=clients.size()) { - NetworkClient* nc=new NetworkClient(client); - clients.push_back(*nc); - //delete nc; - ip = client.remoteIP(); - DIAG(F("New client %d, %d.%d.%d.%d"), clientId, ip[0], ip[1], ip[2], ip[3]); - } - ///} - } - // loop over all connected clients - for (clientId=0; clientId 0) { - // read data from client - byte cmd[len+1]; - for(int i=0; iread(); - if (clientId >= 0) { - // We have data to send in outboundRing - // and we have a valid clientId. - // First read it out to buffer - // and then look if it can be sent because - // we can not leave it in the ring for ever - int count=outboundRing->count(); - { - char buffer[count+1]; // one extra for '\0' - for(int i=0;iread(); - if (c >= 0) // Panic check, should never be false - buffer[i] = (char)c; - else { - DIAG(F("Ringread fail at %d"),i); - break; - } - } - // buffer filled, end with '\0' so we can use it as C string - buffer[count]='\0'; - if((unsigned int)clientId <= clients.size() && clients[clientId].ok()) { - if (Diag::CMD || Diag::WITHROTTLE) - DIAG(F("SEND %d:%s"), clientId, buffer); - clients[clientId].wifi.write(buffer,count); - } else { - DIAG(F("Unsent(%d): %s"), clientId, buffer); - } - } - } - } else if (!APmode) { // in STA mode but not connected any more - // kick it again - if (wlStatus <= 6) { - DIAG(F("Wifi aborted with error %s. Kicking Wifi!"), wlerror[wlStatus]); - // esp_wifi_start(); - // esp_wifi_connect(); - uint8_t tries=40; - while (WiFi.status() != WL_CONNECTED && tries) { - Serial.print('.'); - tries--; - delay(500); - } - } else { - // all well, probably - //DIAG(F("Running BT")); - } - } -}*/ - WiFiClient * clients[MAX_CLIENTS]; // nulled in setup void WifiNINA::checkForNewClient() { @@ -377,6 +220,7 @@ void WifiNINA::checkForNewClient() { for (byte clientId=0; clientIdflush(); // clear out the input buffer DIAG(F("New client connected to slot %d"),clientId); //TJF: brought in for debugging. return; } @@ -428,7 +272,7 @@ void WifiNINA::checkForClientOutput() { } // emit data to the client object // This should work in theory, the - DIAG(F("send message")); //TJF: only for diag + //DIAG(F("send message")); //TJF: only for diag //TJF: the old code had to add a 0x00 byte to the end to terminate the //TJF: c string, before sending it. i take it this is not needed? for (int i=0;iwrite(outboundRing->read()); From 832ec44c67fe1048b82b21c14a1a6d0e4fcae221 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Tue, 7 Nov 2023 06:37:17 -0500 Subject: [PATCH 12/32] clean up IP reading --- Wifi_NINA.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 9664d84..0b595ff 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -114,8 +114,8 @@ bool WifiNINA::setup(const char *SSid, delay(500); } if (WiFi.status() == WL_CONNECTED) { - // String ip_str = sprintf("%xl", WiFi.localIP()); - DIAG(F("Wifi STA IP %d.%d.%d.%d"), WiFi.localIP()[0], WiFi.localIP()[1],WiFi.localIP()[2],WiFi.localIP()[3]); + IPAddress ip = WiFi.localIP(); + DIAG(F("Wifi STA IP %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); wifiUp = true; } else { DIAG(F("Could not connect to Wifi SSID %s"),SSid); @@ -124,17 +124,17 @@ bool WifiNINA::setup(const char *SSid, // esp_wifi_connect(); tries=40; while (WiFi.status() != WL_CONNECTED && tries) { - Serial.print('.'); - tries--; - delay(500); + Serial.print('.'); + tries--; + delay(500); } if (WiFi.status() == WL_CONNECTED) { - ip = WiFi.localIP(); - DIAG(F("Wifi STA IP 2nd try %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); - wifiUp = true; - } else { - DIAG(F("Wifi STA mode FAIL. Will revert to AP mode")); - haveSSID=false; + ip = WiFi.localIP(); + DIAG(F("Wifi STA IP 2nd try %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + wifiUp = true; + } else { + DIAG(F("Wifi STA mode FAIL. Will revert to AP mode")); + haveSSID=false; } } } From 6b731d6f5d90c427a6c2e95257cb43d1eff5d930 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Tue, 7 Nov 2023 13:12:33 -0500 Subject: [PATCH 13/32] fixed timers, still only two tracks --- DCCTimerGiga.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/DCCTimerGiga.cpp b/DCCTimerGiga.cpp index 6b1dd38..3217528 100644 --- a/DCCTimerGiga.cpp +++ b/DCCTimerGiga.cpp @@ -45,8 +45,8 @@ INTERRUPT_CALLBACK interruptHandler=0; //HardwareTimer* timer = NULL; //HardwareTimer* timerAux = NULL; -HardwareTimer timer(TIM2); -HardwareTimer timerAux(TIM3); +HardwareTimer timer(TIM3); +HardwareTimer timerAux(TIM2); static bool tim2ModeHA = false; static bool tim3ModeHA = false; @@ -97,9 +97,9 @@ void DCCTimer::setPWM(byte pin, bool high) { tim3ModeHA = true; } if (high) - TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0; + TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0; else - TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1; + TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1; break; case 13: if (!tim2ModeHA) { @@ -107,9 +107,9 @@ void DCCTimer::setPWM(byte pin, bool high) { tim2ModeHA = true; } if (high) - TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0; + TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0; else - TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1; + TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1; break; } } From 8223d3089235d882957b21c2e6cee1c3877afe8b Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Tue, 7 Nov 2023 14:30:52 -0500 Subject: [PATCH 14/32] added XGIGA config for giga experimental --- MotorDriver.cpp | 19 +++++++++++++++---- MotorDriver.h | 29 ++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 419798f..a28c8a8 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -35,12 +35,21 @@ unsigned long MotorDriver::globalOverloadStart = 0; volatile portreg_t shadowPORTA; volatile portreg_t shadowPORTB; volatile portreg_t shadowPORTC; -#if defined(ARDUINO_ARCH_STM32) +#if defined(ARDUINO_ARCH_STM32) || (defined(ARDUINO_GIGA) && defined(XGIGA)) volatile portreg_t shadowPORTD; volatile portreg_t shadowPORTE; volatile portreg_t shadowPORTF; #endif +#if defined(ARDUINO_GIGA) && defined(XGIGA) +#define STM_PORT(X) (((uint32_t)(X) >> 4) & 0xF) +#define STM_PIN(X) ((uint32_t)(X) & 0xF) +#define STM_GPIO_PIN(X) ((uint16_t)(1<ODR)) +#define portInputRegister(P) (&(P->IDR)) +#endif + MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, int16_t brake_pin, byte current_pin, float sense_factor, unsigned int trip_milliamps, int16_t fault_pin) { const FSH * warnString = F("** WARNING **"); @@ -58,7 +67,7 @@ MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, i getFastPin(F("SIG"),signalPin,fastSignalPin); pinMode(signalPin, OUTPUT); - #ifndef ARDUINO_GIGA // no giga + #if !defined(ARDUINO_GIGA) || (defined(ARDUINO_GIGA) && defined(XGIGA)) // no giga fastSignalPin.shadowinout = NULL; if (HAVE_PORTA(fastSignalPin.inout == &PORTA)) { DIAG(F("Found PORTA pin %d"),signalPin); @@ -97,7 +106,7 @@ MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, i getFastPin(F("SIG2"),signalPin2,fastSignalPin2); pinMode(signalPin2, OUTPUT); - #ifndef ARDUINO_GIGA // no giga + #if !defined(ARDUINO_GIGA) || (defined(ARDUINO_GIGA) && defined(XGIGA)) // no giga fastSignalPin2.shadowinout = NULL; if (HAVE_PORTA(fastSignalPin2.inout == &PORTA)) { DIAG(F("Found PORTA pin %d"),signalPin2); @@ -508,7 +517,7 @@ unsigned int MotorDriver::mA2raw( unsigned int mA) { void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & result) { // DIAG(F("MotorDriver %S Pin=%d,"),type,pin); -#if defined(ARDUINO_GIGA) // yes giga +#if defined(ARDUINO_GIGA) && !defined(XGIGA) // yes giga (void)type; (void)input; // no warnings please @@ -520,6 +529,8 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res PortGroup *port = digitalPinToPort(pin); #elif defined(ARDUINO_ARCH_STM32) GPIO_TypeDef *port = digitalPinToPort(pin); +#elif defined(ARDUINO_GIGA) + auto * port = ((GPIO_TypeDef *)(GPIOA_BASE + (GPIOB_BASE - GPIOA_BASE) * (digitalPinToPinName(pin) >> 4))); #else uint8_t port = digitalPinToPort(pin); #endif diff --git a/MotorDriver.h b/MotorDriver.h index ecc0ae0..32bceb9 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -31,7 +31,7 @@ // use powers of two so we can do logical and/or on the track modes in if clauses. enum TRACK_MODE : byte {TRACK_MODE_NONE = 1, TRACK_MODE_MAIN = 2, TRACK_MODE_PROG = 4, TRACK_MODE_DC = 8, TRACK_MODE_DCX = 16, TRACK_MODE_EXT = 32}; -#if defined(ARDUINO_GIGA) // yes giga +#if defined(ARDUINO_GIGA) && !defined(XGIGA) // yes giga #define setHIGH(fastpin) digitalWrite(fastpin,1) #define setLOW(fastpin) digitalWrite(fastpin,0) @@ -39,7 +39,7 @@ enum TRACK_MODE : byte {TRACK_MODE_NONE = 1, TRACK_MODE_MAIN = 2, TRACK_MODE_PRO #define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH #define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW #endif // giga -#if defined(ARDUINO_GIGA) // yes giga +#if defined(ARDUINO_GIGA) && !defined(XGIGA) // yes giga #define isHIGH(fastpin) ((PinStatus)digitalRead(fastpin)==1) #define isLOW(fastpin) ((PinStatus)digitalRead(fastpin)==0) #else // no giga @@ -82,6 +82,25 @@ enum TRACK_MODE : byte {TRACK_MODE_NONE = 1, TRACK_MODE_MAIN = 2, TRACK_MODE_PRO #endif #endif +#if defined(ARDUINO_GIGA) && defined(XGIGA) +#define PORTA GPIOA->ODR +#define HAVE_PORTA(X) X +#define PORTB GPIOB->ODR +#define HAVE_PORTB(X) X +#define PORTC GPIOC->ODR +#define HAVE_PORTC(X) X +#define PORTD GPIOD->ODR +#define HAVE_PORTD(X) X +#if defined(GPIOE) +#define PORTE GPIOE->ODR +#define HAVE_PORTE(X) X +#endif +#if defined(GPIOF) +#define PORTF GPIOF->ODR +#define HAVE_PORTF(X) X +#endif +#endif + // if macros not defined as pass-through we define // them here as someting that is valid as a // statement and evaluates to false. @@ -121,13 +140,13 @@ public: byte invpin = UNUSED_PIN; }; -#if defined(__IMXRT1062__) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) +#if defined(__IMXRT1062__) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) || (defined(ARDUINO_GIGA) && defined(XGIGA)) typedef uint32_t portreg_t; #else typedef uint8_t portreg_t; #endif -#if defined(ARDUINO_GIGA) // yes giga +#if defined(ARDUINO_GIGA) && !defined(XGIGA) // yes giga typedef int FASTPIN; @@ -165,7 +184,7 @@ class MotorDriver { // otherwise the call from interrupt context can undo whatever we do // from outside interrupt void setBrake( bool on, bool interruptContext=false); - #if defined(ARDUINO_GIGA) // yes giga + #if defined(ARDUINO_GIGA) && !defined(XGIGA) // yes giga __attribute__((always_inline)) inline void setSignal( bool high) { digitalWrite(signalPin, high); if (dualSignal) digitalWrite(signalPin2, !high); From f254643a1da13f5a32c4781618e208f03ce76c77 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Tue, 7 Nov 2023 16:37:38 -0500 Subject: [PATCH 15/32] added note about SystemCoreClock --- DCCTimer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/DCCTimer.h b/DCCTimer.h index ce4a618..cae2163 100644 --- a/DCCTimer.h +++ b/DCCTimer.h @@ -92,6 +92,7 @@ private: #if defined(ARDUINO_ARCH_STM32) // TODO: PMA temporary hack - assumes 100Mhz F_CPU as STM32 can change frequency static const long CLOCK_CYCLES=(100000000L / 1000000 * DCC_SIGNAL_TIME) >>1; #elif defined(ARDUINO_GIGA) + ///TJF: we could get F_CPU from SystemCoreClock, but it will not allow as it is a non-constant value static const long CLOCK_CYCLES=(480000000L / 1000000 * DCC_SIGNAL_TIME) >>1; #else static const long CLOCK_CYCLES=(F_CPU / 1000000 * DCC_SIGNAL_TIME) >>1; From c458e98cd3d7e0691ae96b80d166cd3c19861054 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Wed, 8 Nov 2023 13:40:39 -0500 Subject: [PATCH 16/32] digitalPinToPort back from arduino core --- MotorDriver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MotorDriver.cpp b/MotorDriver.cpp index a28c8a8..b0b298a 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -530,7 +530,8 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res #elif defined(ARDUINO_ARCH_STM32) GPIO_TypeDef *port = digitalPinToPort(pin); #elif defined(ARDUINO_GIGA) - auto * port = ((GPIO_TypeDef *)(GPIOA_BASE + (GPIOB_BASE - GPIOA_BASE) * (digitalPinToPinName(pin) >> 4))); + //auto * port = ((GPIO_TypeDef *)(GPIOA_BASE + (GPIOB_BASE - GPIOA_BASE) * (digitalPinToPinName(pin) >> 4))); + GPIO_TypeDef *port = (GPIO_TypeDef *)digitalPinToPort(pin); #else uint8_t port = digitalPinToPort(pin); #endif From 5c0ab9a31100bf22f3174dab1ffd983a6b7698a0 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 10 Nov 2023 08:56:21 -0500 Subject: [PATCH 17/32] pre-test storing of signal updates --- DCCTimerGiga.cpp | 92 ++++++++++++++++++------------------------------ TrackManager.h | 5 ++- 2 files changed, 39 insertions(+), 58 deletions(-) diff --git a/DCCTimerGiga.cpp b/DCCTimerGiga.cpp index 3217528..3ac964c 100644 --- a/DCCTimerGiga.cpp +++ b/DCCTimerGiga.cpp @@ -43,14 +43,19 @@ INTERRUPT_CALLBACK interruptHandler=0; -//HardwareTimer* timer = NULL; -//HardwareTimer* timerAux = NULL; -HardwareTimer timer(TIM3); -HardwareTimer timerAux(TIM2); - -static bool tim2ModeHA = false; -static bool tim3ModeHA = false; +#ifndef DCC_EX_TIMER +#if defined(TIM6) +#define DCC_EX_TIMER TIM6 +#elif defined(TIM7) +#define DCC_EX_TIMER TIM7 +#elif defined(TIM12) +#define DCC_EX_TIMER TIM12 +#else +#warning This Giga variant does not have Timers 1,8 or 11!! +#endif +#endif // ifndef DCC_EX_TIMER +HardwareTimer dcctimer(TIM8); void DCCTimer_Handler() __attribute__((interrupt)); void DCCTimer_Handler() { @@ -59,66 +64,38 @@ void DCCTimer_Handler() { void DCCTimer::begin(INTERRUPT_CALLBACK callback) { interruptHandler=callback; - noInterrupts(); - - // adc_set_sample_rate(ADC_SAMPLETIME_480CYCLES); - timer.pause(); - timerAux.pause(); - timer.setPrescaleFactor(1); - timer.setOverflow(DCC_SIGNAL_TIME, MICROSEC_FORMAT); - timer.attachInterrupt(DCCTimer_Handler); - timer.refresh(); - timerAux.setPrescaleFactor(1); - timerAux.setOverflow(DCC_SIGNAL_TIME, MICROSEC_FORMAT); - timerAux.refresh(); + noInterrupts(); - timer.resume(); - timerAux.resume(); + dcctimer.pause(); + dcctimer.setPrescaleFactor(1); +// timer.setOverflow(CLOCK_CYCLES * 2); + dcctimer.setOverflow(DCC_SIGNAL_TIME, MICROSEC_FORMAT); + // dcctimer.attachInterrupt(Timer11_Handler); + dcctimer.attachInterrupt(DCCTimer_Handler); + dcctimer.setInterruptPriority(0, 0); // Set highest preemptive priority! + dcctimer.refresh(); + dcctimer.resume(); - interrupts(); + interrupts(); } bool DCCTimer::isPWMPin(byte pin) { - switch (pin) { - case 12: - return true; - case 13: - return true; - default: - return false; - } + //TODO: STM32 whilst this call to digitalPinHasPWM will reveal which pins can do PWM, + // there's no support yet for High Accuracy, so for now return false + // return digitalPinHasPWM(pin); + (void) pin; + return false; } void DCCTimer::setPWM(byte pin, bool high) { - switch (pin) { - case 12: - if (!tim3ModeHA) { - timerAux.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, 12); - tim3ModeHA = true; - } - if (high) - TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0; - else - TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1; - break; - case 13: - if (!tim2ModeHA) { - timer.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, 13); - tim2ModeHA = true; - } - if (high) - TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0; - else - TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1; - break; - } + // TODO: High Accuracy mode is not supported as yet, and may never need to be + (void) pin; + (void) high; + return; } void DCCTimer::clearPWM() { - timer.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, NC); - tim2ModeHA = false; - timerAux.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, NC); - tim3ModeHA = false; + return; } void DCCTimer::getSimulatedMacAddress(byte mac[6]) { @@ -161,6 +138,7 @@ void DCCTimer::reset() { //Watchdog::start(500); //while(true) {}; + return; } int * ADCee::analogvals = NULL; @@ -170,7 +148,7 @@ int16_t ADCee::ADCmax() return 1023; } -AdvancedADC adc(A0, A1); +AdvancedADC adc(A0, A1, A2, A3); int ADCee::init(uint8_t pin) { adc.begin(AN_RESOLUTION_10, 16000, 1, 512); return 123; diff --git a/TrackManager.h b/TrackManager.h index d197751..b098073 100644 --- a/TrackManager.h +++ b/TrackManager.h @@ -72,8 +72,11 @@ class TrackManager { static void setJoinPower(POWERMODE mode) {setPower2(false,true,mode);} static void setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byte thistrack); - +#if defined(ARduINO_GIGA) // yes giga + static const int16_t MAX_TRACKS=4; +#else // no giga static const int16_t MAX_TRACKS=8; +#endif // giga static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0); static bool parseJ(Print * stream, int16_t params, int16_t p[]); static void loop(); From 36db7244660920ffa77df0ccd0a4f12930cd73f6 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 10 Nov 2023 09:17:39 -0500 Subject: [PATCH 18/32] fixed Typo --- TrackManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrackManager.h b/TrackManager.h index b098073..1c68bc5 100644 --- a/TrackManager.h +++ b/TrackManager.h @@ -72,7 +72,7 @@ class TrackManager { static void setJoinPower(POWERMODE mode) {setPower2(false,true,mode);} static void setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byte thistrack); -#if defined(ARduINO_GIGA) // yes giga +#if defined(ARDUINO_GIGA) // yes giga static const int16_t MAX_TRACKS=4; #else // no giga static const int16_t MAX_TRACKS=8; From 40c0c20df88d39581d9f3cb18d7655a753b260f2 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 10 Nov 2023 10:46:14 -0500 Subject: [PATCH 19/32] Post tests - PASSED --- TrackManager.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/TrackManager.h b/TrackManager.h index 1c68bc5..d197751 100644 --- a/TrackManager.h +++ b/TrackManager.h @@ -72,11 +72,8 @@ class TrackManager { static void setJoinPower(POWERMODE mode) {setPower2(false,true,mode);} static void setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byte thistrack); -#if defined(ARDUINO_GIGA) // yes giga - static const int16_t MAX_TRACKS=4; -#else // no giga + static const int16_t MAX_TRACKS=8; -#endif // giga static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0); static bool parseJ(Print * stream, int16_t params, int16_t p[]); static void loop(); From 904fd5a780f6c55935922c850236debbdacf5d0e Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 10 Nov 2023 13:36:40 -0500 Subject: [PATCH 20/32] possible fix for 4+ tracks --- DCCTimerGiga.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/DCCTimerGiga.cpp b/DCCTimerGiga.cpp index 3ac964c..9763878 100644 --- a/DCCTimerGiga.cpp +++ b/DCCTimerGiga.cpp @@ -148,9 +148,15 @@ int16_t ADCee::ADCmax() return 1023; } -AdvancedADC adc(A0, A1, A2, A3); +AdvancedADC adc; +pin_size_t active_pins[] = {A0, A1, A2, A3}; +pin_size_t active_pinsB[] = {A4, A5, A6, A7}; +int num_active_pins = 4; +const int samples_per_round = 3; int ADCee::init(uint8_t pin) { - adc.begin(AN_RESOLUTION_10, 16000, 1, 512); + adc.stop(); + if (pin >= A0 && pin <= A3) adc.begin(AN_RESOLUTION_16, 2, 1, samples_per_round, num_active_pins, active_pins); + else if (pin >= A4 && pin <= A7) adc.begin(AN_RESOLUTION_16, 2, 1, samples_per_round, num_active_pins, active_pinsB); return 123; } @@ -158,13 +164,16 @@ int ADCee::init(uint8_t pin) { * Read function ADCee::read(pin) to get value instead of analogRead(pin) */ int ADCee::read(uint8_t pin, bool fromISR) { + int tmpPin = 0; + if (pin >= A0 && pin <= A3) tmpPin = (pin - A0); + else if (pin >= A4 && pin <= A7) tmpPin = ((pin - A0) - 4); static SampleBuffer buf = adc.read(); int retVal = -123; if (adc.available()) { buf.release(); buf = adc.read(); } - return (buf[pin - A0]); + return (buf[tmpPin]); } /* From 9a6a305fc5959d56d726d726892a6889300ea9c5 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 10 Nov 2023 14:24:14 -0500 Subject: [PATCH 21/32] so far, 8 good signals, one (tested) is DC --- DCCTimerGiga.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DCCTimerGiga.cpp b/DCCTimerGiga.cpp index 9763878..598c419 100644 --- a/DCCTimerGiga.cpp +++ b/DCCTimerGiga.cpp @@ -152,11 +152,11 @@ AdvancedADC adc; pin_size_t active_pins[] = {A0, A1, A2, A3}; pin_size_t active_pinsB[] = {A4, A5, A6, A7}; int num_active_pins = 4; -const int samples_per_round = 3; +const int samples_per_round = 512; int ADCee::init(uint8_t pin) { adc.stop(); - if (pin >= A0 && pin <= A3) adc.begin(AN_RESOLUTION_16, 2, 1, samples_per_round, num_active_pins, active_pins); - else if (pin >= A4 && pin <= A7) adc.begin(AN_RESOLUTION_16, 2, 1, samples_per_round, num_active_pins, active_pinsB); + if (pin >= A0 && pin <= A3) adc.begin(AN_RESOLUTION_10, 16000, 1, samples_per_round, num_active_pins, active_pins); + else if (pin >= A4 && pin <= A7) adc.begin(AN_RESOLUTION_10, 16000, 1, samples_per_round, num_active_pins, active_pinsB); return 123; } From 98f00300ec26018d040dfd9a39ca46066dba9150 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Fri, 10 Nov 2023 15:09:56 -0500 Subject: [PATCH 22/32] removed I2C port change option as it is breaking --- I2CManager_Wire.h | 48 ++++++++++++++++++++++------------------------- defines.h | 8 -------- 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/I2CManager_Wire.h b/I2CManager_Wire.h index 69ffc96..db2ae0c 100644 --- a/I2CManager_Wire.h +++ b/I2CManager_Wire.h @@ -35,11 +35,7 @@ #define WIRE_HAS_TIMEOUT #endif -#if defined(GIGA_I2C_1) -#define DCCEX_WIRE Wire1 -#else -#define DCCEX_WIRE Wire -#endif + @@ -47,9 +43,9 @@ * Initialise I2C interface software ***************************************************************************/ void I2CManagerClass::_initialise() { - DCCEX_WIRE.begin(); + Wire.begin(); #if defined(WIRE_HAS_TIMEOUT) - DCCEX_WIRE.setWireTimeout(_timeout, true); + Wire.setWireTimeout(_timeout, true); #endif } @@ -58,7 +54,7 @@ void I2CManagerClass::_initialise() { * on Arduino. Mega4809 supports 1000000 (Fast+) too. ***************************************************************************/ void I2CManagerClass::_setClock(unsigned long i2cClockSpeed) { - DCCEX_WIRE.setClock(i2cClockSpeed); + Wire.setClock(i2cClockSpeed); } /*************************************************************************** @@ -69,7 +65,7 @@ void I2CManagerClass::_setClock(unsigned long i2cClockSpeed) { void I2CManagerClass::setTimeout(unsigned long value) { _timeout = value; #if defined(WIRE_HAS_TIMEOUT) - DCCEX_WIRE.setWireTimeout(value, true); + Wire.setWireTimeout(value, true); #endif } @@ -82,7 +78,7 @@ static uint8_t muxSelect(I2CAddress address) { I2CMux muxNo = address.muxNumber(); I2CSubBus subBus = address.subBus(); if (muxNo != I2CMux_None) { - DCCEX_WIRE.beginTransmission(I2C_MUX_BASE_ADDRESS+muxNo); + Wire.beginTransmission(I2C_MUX_BASE_ADDRESS+muxNo); uint8_t data = (subBus == SubBus_All) ? 0xff : (subBus == SubBus_None) ? 0x00 : #if defined(I2CMUX_PCA9547) @@ -94,8 +90,8 @@ static uint8_t muxSelect(I2CAddress address) { // with a bit set for the subBus to be enabled 1 << subBus; #endif - DCCEX_WIRE.write(&data, 1); - return DCCEX_WIRE.endTransmission(true); // have to release I2C bus for it to work + Wire.write(&data, 1); + return Wire.endTransmission(true); // have to release I2C bus for it to work } return I2C_STATUS_OK; } @@ -118,9 +114,9 @@ uint8_t I2CManagerClass::write(I2CAddress address, const uint8_t buffer[], uint8 #endif // Only send new transaction if address is non-zero. if (muxStatus == I2C_STATUS_OK && address != 0) { - DCCEX_WIRE.beginTransmission(address); - if (size > 0) DCCEX_WIRE.write(buffer, size); - status = DCCEX_WIRE.endTransmission(); + Wire.beginTransmission(address); + if (size > 0) Wire.write(buffer, size); + status = Wire.endTransmission(); } #ifdef I2C_EXTENDED_ADDRESS // Deselect MUX if there's more than one MUX present, to avoid having multiple ones selected @@ -169,25 +165,25 @@ uint8_t I2CManagerClass::read(I2CAddress address, uint8_t readBuffer[], uint8_t // Only start new transaction if address is non-zero. if (muxStatus == I2C_STATUS_OK && address != 0) { if (writeSize > 0) { - DCCEX_WIRE.beginTransmission(address); - DCCEX_WIRE.write(writeBuffer, writeSize); - status = DCCEX_WIRE.endTransmission(false); // Don't free bus yet + Wire.beginTransmission(address); + Wire.write(writeBuffer, writeSize); + status = Wire.endTransmission(false); // Don't free bus yet } if (status == I2C_STATUS_OK) { #ifdef WIRE_HAS_TIMEOUT - DCCEX_WIRE.clearWireTimeoutFlag(); - DCCEX_WIRE.requestFrom(address, (size_t)readSize); - if (!DCCEX_WIRE.getWireTimeoutFlag()) { - while (DCCEX_WIRE.available() && nBytes < readSize) - readBuffer[nBytes++] = DCCEX_WIRE.read(); + Wire.clearWireTimeoutFlag(); + Wire.requestFrom(address, (size_t)readSize); + if (!Wire.getWireTimeoutFlag()) { + while (Wire.available() && nBytes < readSize) + readBuffer[nBytes++] = Wire.read(); if (nBytes < readSize) status = I2C_STATUS_TRUNCATED; } else { status = I2C_STATUS_TIMEOUT; } #else - DCCEX_WIRE.requestFrom(address, (size_t)readSize); - while (DCCEX_WIRE.available() && nBytes < readSize) - readBuffer[nBytes++] = DCCEX_WIRE.read(); + Wire.requestFrom(address, (size_t)readSize); + while (Wire.available() && nBytes < readSize) + readBuffer[nBytes++] = Wire.read(); if (nBytes < readSize) status = I2C_STATUS_TRUNCATED; #endif } diff --git a/defines.h b/defines.h index 8c5ada4..756e45a 100644 --- a/defines.h +++ b/defines.h @@ -161,14 +161,6 @@ //#endif #define SDA I2C_SDA #define SCL I2C_SCL - #define DCC_EX_TIMER - // these don't work... - //extern const uint16_t PROGMEM port_to_input_PGM[]; - //extern const uint16_t PROGMEM port_to_output_PGM[]; - //extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; - //#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) - //#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) - //#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) /* TODO when ready #elif defined(ARDUINO_ARCH_RP2040) From 83a22dfae561f7dcf5eac763bdac16e843b6e99f Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Sun, 12 Nov 2023 04:44:59 -0500 Subject: [PATCH 23/32] 12-bit analog, vs just 10-bit --- DCCTimerGiga.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DCCTimerGiga.cpp b/DCCTimerGiga.cpp index 598c419..2d70785 100644 --- a/DCCTimerGiga.cpp +++ b/DCCTimerGiga.cpp @@ -145,7 +145,7 @@ int * ADCee::analogvals = NULL; int16_t ADCee::ADCmax() { - return 1023; + return 4095; } AdvancedADC adc; @@ -155,8 +155,8 @@ int num_active_pins = 4; const int samples_per_round = 512; int ADCee::init(uint8_t pin) { adc.stop(); - if (pin >= A0 && pin <= A3) adc.begin(AN_RESOLUTION_10, 16000, 1, samples_per_round, num_active_pins, active_pins); - else if (pin >= A4 && pin <= A7) adc.begin(AN_RESOLUTION_10, 16000, 1, samples_per_round, num_active_pins, active_pinsB); + if (pin >= A0 && pin <= A3) adc.begin(AN_RESOLUTION_12, 16000, 1, samples_per_round, num_active_pins, active_pins); + else if (pin >= A4 && pin <= A7) adc.begin(AN_RESOLUTION_12, 16000, 1, samples_per_round, num_active_pins, active_pinsB); return 123; } From 35d124724005f98b445127a59ad9f5b99917493b Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Tue, 14 Nov 2023 16:27:21 -0500 Subject: [PATCH 24/32] commit current --- Wifi_NINA.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 0b595ff..bef800c 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -81,7 +81,7 @@ bool WifiNINA::setup(const char *SSid, uint8_t tries = 40; // Set up the pins! -#ifndef GIGA_WIFI +#if !defined(GIGA_WIFI) WiFi.setPins(SPIWIFI_SS, SPIWIFI_ACK, ESP32_RESETN, ESP32_GPIO0, &SPIWIFI); #endif // check for the WiFi module: @@ -193,7 +193,6 @@ bool WifiNINA::setup(const char *SSid, server = new WiFiServer(port); // start listening on tcp port server->begin(); // server started here - DIAG(F("Server will be started on port %d"),port); ip = WiFi.localIP(); From 961470302d1105a79be35614cd66db9924fc1911 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Thu, 16 Nov 2023 09:40:08 -0500 Subject: [PATCH 25/32] getting rid of a comment --- Wifi_NINA.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index bef800c..a7c3f9b 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -234,7 +234,7 @@ void WifiNINA::checkForLostClients() { DIAG(F("Remove client %d"), clientId); CommandDistributor::forget(clientId); //delete c; //TJF: this causes a crash when client drops.. commenting out for now. - clients[clientId]=nullptr; // TJF: what to do... what to do... + clients[clientId]=nullptr; } } } From 7f430ce6bd759b0d3835976bde0040529459ada6 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Sat, 18 Nov 2023 13:10:29 -0500 Subject: [PATCH 26/32] current --- Wifi_NINA.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index a7c3f9b..52efce1 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -249,7 +249,7 @@ void WifiNINA::checkForClientInput() { // read data from client byte cmd[len+1]; for(int i=0; iread(); - cmd[len]=0; + cmd[len]=0x00; CommandDistributor::parse(clientId,cmd,outboundRing); } } @@ -275,6 +275,7 @@ void WifiNINA::checkForClientOutput() { //TJF: the old code had to add a 0x00 byte to the end to terminate the //TJF: c string, before sending it. i take it this is not needed? for (int i=0;iwrite(outboundRing->read()); + //c->write((byte)0x00); } void WifiNINA::loop() { From 330bdf58a15857ceee237c5ab4f1bbb9f064adbf Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Sat, 18 Nov 2023 13:43:31 -0500 Subject: [PATCH 27/32] works, but uses multi connects per client --- Wifi_NINA.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 52efce1..ea271d5 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -219,7 +219,7 @@ void WifiNINA::checkForNewClient() { for (byte clientId=0; clientIdflush(); // clear out the input buffer + ///clients[clientId]->flush(); // clear out the input buffer DIAG(F("New client connected to slot %d"),clientId); //TJF: brought in for debugging. return; } From 1d881a4b43e76b31ea5d82263d083f7c61ed664f Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Sat, 18 Nov 2023 14:07:19 -0500 Subject: [PATCH 28/32] cleaning up --- Wifi_NINA.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index ea271d5..4672d85 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -219,7 +219,6 @@ void WifiNINA::checkForNewClient() { for (byte clientId=0; clientIdflush(); // clear out the input buffer DIAG(F("New client connected to slot %d"),clientId); //TJF: brought in for debugging. return; } @@ -233,7 +232,6 @@ void WifiNINA::checkForLostClients() { clients[clientId]->stop(); DIAG(F("Remove client %d"), clientId); CommandDistributor::forget(clientId); - //delete c; //TJF: this causes a crash when client drops.. commenting out for now. clients[clientId]=nullptr; } } @@ -270,12 +268,7 @@ void WifiNINA::checkForClientOutput() { return; } // emit data to the client object - // This should work in theory, the - //DIAG(F("send message")); //TJF: only for diag - //TJF: the old code had to add a 0x00 byte to the end to terminate the - //TJF: c string, before sending it. i take it this is not needed? for (int i=0;iwrite(outboundRing->read()); - //c->write((byte)0x00); } void WifiNINA::loop() { From 5aca3a62d849d70a56465d4c48a40f8526b623ea Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Sun, 19 Nov 2023 03:09:53 -0500 Subject: [PATCH 29/32] solved WiFiNINA reset/restart bug --- Wifi_NINA.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Wifi_NINA.cpp b/Wifi_NINA.cpp index 4672d85..1cd71a8 100644 --- a/Wifi_NINA.cpp +++ b/Wifi_NINA.cpp @@ -122,6 +122,8 @@ bool WifiNINA::setup(const char *SSid, DIAG(F("Forcing one more Wifi restart")); // esp_wifi_start(); // esp_wifi_connect(); + WiFi.end(); + WiFi.begin(SSid, password); tries=40; while (WiFi.status() != WL_CONNECTED && tries) { Serial.print('.'); @@ -219,7 +221,7 @@ void WifiNINA::checkForNewClient() { for (byte clientId=0; clientIdconnected()) { clients[clientId]->stop(); - DIAG(F("Remove client %d"), clientId); + //DIAG(F("Remove client %d"), clientId); CommandDistributor::forget(clientId); clients[clientId]=nullptr; } @@ -264,7 +266,7 @@ void WifiNINA::checkForClientOutput() { if (!c) { // client is gone, throw away msg for (int i=0;iread(); - DIAG(F("gone, drop message.")); //TJF: only for diag + //DIAG(F("gone, drop message.")); //TJF: only for diag return; } // emit data to the client object From 1a4fff89248eaf30407db943cbc41960dc2c08f7 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Sun, 19 Nov 2023 15:27:26 -0500 Subject: [PATCH 30/32] adding more locos for Giga --- DCC.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DCC.h b/DCC.h index 74b4e77..2ac5ab9 100644 --- a/DCC.h +++ b/DCC.h @@ -43,7 +43,11 @@ const uint16_t LONG_ADDR_MARKER = 0x4000; // Allocations with memory implications..! // Base system takes approx 900 bytes + 8 per loco. Turnouts, Sensors etc are dynamically created #if defined(HAS_ENOUGH_MEMORY) +#if defined(ARDUINO_GIGA) // yes giga +const byte MAX_LOCOS = 100; +#else // no giga const byte MAX_LOCOS = 50; +#endif // giga #else const byte MAX_LOCOS = 30; #endif From 5906735c56796dc969d1baf3096096b30b0508ca Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Sun, 19 Nov 2023 16:55:06 -0500 Subject: [PATCH 31/32] patching in PR # 366 --- StringFormatter.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/StringFormatter.cpp b/StringFormatter.cpp index b40de1c..0424ef3 100644 --- a/StringFormatter.cpp +++ b/StringFormatter.cpp @@ -39,11 +39,11 @@ void StringFormatter::diag( const FSH* input...) { void StringFormatter::lcd(byte row, const FSH* input...) { va_list args; - // Issue the LCD as a diag first - send(&USB_SERIAL,F("<* LCD%d:"),row); + // Copy to serial client for display 0 <@ display# line# "message"> + send(&USB_SERIAL,F("<@ 0 %d \""),row); va_start(args, input); send2(&USB_SERIAL,input,args); - send(&USB_SERIAL,F(" *>\n")); + send(&USB_SERIAL,F("\">\n")); DisplayInterface::setRow(row); va_start(args, input); @@ -53,6 +53,12 @@ void StringFormatter::lcd(byte row, const FSH* input...) { void StringFormatter::lcd2(uint8_t display, byte row, const FSH* input...) { va_list args; + // Copy to serial client <@ display# line# "message"> + send(&USB_SERIAL,F("<@ %d %d \""),display,row); + va_start(args, input); + send2(&USB_SERIAL,input,args); + send(&USB_SERIAL,F("\">\n")); + DisplayInterface::setRow(display, row); va_start(args, input); send2(DisplayInterface::getDisplayHandler(),input,args); From d690b09bb0f72a3701c7ce4032d5d1fd821ed153 Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Mon, 20 Nov 2023 03:52:11 -0500 Subject: [PATCH 32/32] parse "@" --- CommandDistributor.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++ CommandDistributor.h | 8 +++++++ DCCEXParser.cpp | 7 +++++++ 3 files changed, 62 insertions(+) diff --git a/CommandDistributor.cpp b/CommandDistributor.cpp index 1651771..bee34d9 100644 --- a/CommandDistributor.cpp +++ b/CommandDistributor.cpp @@ -272,3 +272,50 @@ void CommandDistributor::broadcastRaw(clientType type, char * msg) { void CommandDistributor::broadcastTrackState(const FSH* format,byte trackLetter, int16_t dcAddr) { broadcastReply(COMMAND_TYPE, format,trackLetter, dcAddr); } + +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; \ No newline at end of file diff --git a/CommandDistributor.h b/CommandDistributor.h index d54ef31..43f4b09 100644 --- a/CommandDistributor.h +++ b/CommandDistributor.h @@ -59,6 +59,14 @@ public : template static void broadcastReply(clientType type, Targs... msg); static void forget(byte clientId); + // 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 d79136f..96bf4c7 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -913,6 +913,13 @@ 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); + StringFormatter::send(stream, + F("<@ 0 0 \"DCC-EX v" VERSION "\">\n" + "<@ 0 1 \"Lic GPLv3\">\n")); + 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++)