diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 45327ba..a133a2e 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -117,6 +117,9 @@ Once a new OPCODE is decided upon, update this list. #include "Turntables.h" #include "version.h" #include "KeywordHasher.h" +#ifdef ARDUINO_ARCH_ESP32 +#include "WifiESP32.h" +#endif // This macro can't be created easily as a portable function because the // flashlist requires a far pointer for high flash access. @@ -140,12 +143,12 @@ byte DCCEXParser::stashTarget=0; // Non-DCC things like turnouts, pins and sensors are handled in additional JMRI interface classes. -int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], const byte *cmd, bool usehex) +int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], byte *cmd, bool usehex) { byte state = 1; byte parameterCount = 0; int16_t runningValue = 0; - const byte *remainingCmd = cmd + 1; // skips the opcode + byte *remainingCmd = cmd + 1; // skips the opcode bool signNegative = false; // clear all parameters in case not enough found @@ -155,7 +158,6 @@ int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], const byte while (parameterCount < MAX_COMMAND_PARAMS) { byte hot = *remainingCmd; - switch (state) { @@ -169,7 +171,22 @@ int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], const byte state = 2; continue; - case 2: // checking sign + case 2: // checking sign or quoted string +#ifdef HAS_ENOUGH_MEMORY + if (hot == '"') { + // this inserts an extra parameter 0x7777 in front + // of each string parameter as a marker that can + // be checked that a string parameter follows + // This clashes of course with the real value + // 0x7777 which we hope is used seldom + result[parameterCount] = (int16_t)0x7777; + parameterCount++; + result[parameterCount] = (int16_t)(remainingCmd - cmd + 1); + parameterCount++; + state = 4; + break; + } +#endif signNegative = false; runningValue = 0; state = 3; @@ -200,6 +217,16 @@ int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], const byte parameterCount++; state = 1; continue; +#ifdef HAS_ENOUGH_MEMORY + case 4: // skipover text + if (hot == '\0') // We did run to end of buffer without finding the " + return -1; + if (hot == '"') { + *remainingCmd = '\0'; // overwrite " in command buffer with the end-of-string + state = 1; + } + break; +#endif } remainingCmd++; } @@ -645,9 +672,22 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) StringFormatter::send(stream, F("\n")); return; case 'C': // CONFIG - if (parseC(stream, params, p)) - return; - break; +#if defined(ARDUINO_ARCH_ESP32) +// currently this only works on ESP32 +#if defined(HAS_ENOUGH_MEMORY) + if (p[0] == "WIFI"_hk) { // + if (params != 5) // the 5 params 0 to 4 are (kinda): WIFI_hk 0x7777 &SSID 0x7777 &PASSWORD + break; + if (p[1] == 0x7777 && p[3] == 0x7777) { + WifiESP::setup((const char*)(com + p[2]), (const char*)(com + p[4]), WIFI_HOSTNAME, IP_PORT, WIFI_CHANNEL, WIFI_FORCE_AP); + } + return; + } +#endif +#endif //ESP32 + if (parseC(stream, params, p)) + return; + break; #ifndef DISABLE_DIAG case 'D': // DIAG if (parseD(stream, params, p)) @@ -1140,8 +1180,7 @@ bool DCCEXParser::parseC(Print *stream, int16_t params, int16_t p[]) { } return true; #endif - -default: // invalid/unknown + default: // invalid/unknown break; } return false; diff --git a/DCCEXParser.h b/DCCEXParser.h index d3b7851..b9d56ea 100644 --- a/DCCEXParser.h +++ b/DCCEXParser.h @@ -43,7 +43,7 @@ struct DCCEXParser private: static const int16_t MAX_BUFFER=50; // longest command sent in - static int16_t splitValues( int16_t result[MAX_COMMAND_PARAMS], const byte * command, bool usehex); + static int16_t splitValues( int16_t result[MAX_COMMAND_PARAMS], byte * command, bool usehex); static bool parseT(Print * stream, int16_t params, int16_t p[]); static bool parseZ(Print * stream, int16_t params, int16_t p[]); diff --git a/SerialManager.cpp b/SerialManager.cpp index fa7ad38..5dfa526 100644 --- a/SerialManager.cpp +++ b/SerialManager.cpp @@ -1,7 +1,7 @@ /* * © 2022 Paul M. Antoine * © 2021 Chris Harlow - * © 2022 Harald Barth + * © 2022 2024 Harald Barth * All rights reserved. * * This file is part of DCC++EX @@ -23,6 +23,7 @@ #include "SerialManager.h" #include "DCCEXParser.h" #include "StringFormatter.h" +#include "DIAG.h" #ifdef ARDUINO_ARCH_ESP32 #ifdef SERIAL_BT_COMMANDS @@ -36,6 +37,10 @@ BluetoothSerial SerialBT; #endif //COMMANDS #endif //ESP32 +static const byte PAYLOAD_FALSE = 0; +static const byte PAYLOAD_NORMAL = 1; +static const byte PAYLOAD_STRING = 2; + SerialManager * SerialManager::first=NULL; SerialManager::SerialManager(Stream * myserial) { @@ -43,7 +48,7 @@ SerialManager::SerialManager(Stream * myserial) { next=first; first=this; bufferLength=0; - inCommandPayload=false; + inCommandPayload=PAYLOAD_FALSE; } void SerialManager::init() { @@ -112,23 +117,39 @@ void SerialManager::loop() { } void SerialManager::loop2() { - while (serial->available()) { - char ch = serial->read(); - if (ch == '<') { - inCommandPayload = true; - bufferLength = 0; - buffer[0] = '\0'; - } - else if (inCommandPayload) { - if (bufferLength < (COMMAND_BUFFER_SIZE-1)) - buffer[bufferLength++] = ch; - if (ch == '>') { - buffer[bufferLength] = '\0'; - DCCEXParser::parse(serial, buffer, NULL); - inCommandPayload = false; - break; - } + while (serial->available()) { + char ch = serial->read(); + if (!inCommandPayload) { + if (ch == '<') { + inCommandPayload = PAYLOAD_NORMAL; + bufferLength = 0; + buffer[0] = '\0'; + } + } else { // if (inCommandPayload) + if (bufferLength < (COMMAND_BUFFER_SIZE-1)) + buffer[bufferLength++] = ch; + if (inCommandPayload > PAYLOAD_NORMAL) { + if (inCommandPayload > 32 + 2) { // String way too long + ch = '>'; // we end this nonsense + inCommandPayload = PAYLOAD_NORMAL; + DIAG(F("Parse error: Unbalanced string")); + // fall through to ending parsing below + } else if (ch == '"') { // String end + inCommandPayload = PAYLOAD_NORMAL; + continue; // do not fall through + } else + inCommandPayload++; + } + if (inCommandPayload == PAYLOAD_NORMAL) { + if (ch == '>') { + buffer[bufferLength] = '\0'; + DCCEXParser::parse(serial, buffer, NULL); + inCommandPayload = PAYLOAD_FALSE; + break; + } else if (ch == '"') { + inCommandPayload = PAYLOAD_STRING; } + } } - + } } diff --git a/SerialManager.h b/SerialManager.h index ad1eaf3..5277e68 100644 --- a/SerialManager.h +++ b/SerialManager.h @@ -44,6 +44,6 @@ private: SerialManager * next; byte bufferLength; byte buffer[COMMAND_BUFFER_SIZE]; - bool inCommandPayload; + byte inCommandPayload; }; #endif diff --git a/WifiESP32.cpp b/WifiESP32.cpp index d44672a..227484c 100644 --- a/WifiESP32.cpp +++ b/WifiESP32.cpp @@ -23,13 +23,13 @@ #include #include "defines.h" #include "ESPmDNS.h" -#include #include "esp_wifi.h" #include "WifiESP32.h" #include "DIAG.h" #include "RingStream.h" #include "CommandDistributor.h" #include "WiThrottle.h" +#include "DCC.h" /* #include "soc/rtc_wdt.h" #include "esp_task_wdt.h" @@ -109,10 +109,13 @@ private: bool inUse; }; +// file scope variables static std::vector clients; // a list to hold all clients -static WiFiServer *server = NULL; static RingStream *outboundRing = new RingStream(10240); static bool APmode = false; +// init of static class scope variables +bool WifiESP::wifiUp = false; +WiFiServer *WifiESP::server = NULL; #ifdef WIFI_TASK_ON_CORE0 void wifiLoop(void *){ @@ -128,6 +131,30 @@ char asciitolower(char in) { return in; } +void WifiESP::teardown() { + // stop all locos + DCC::setThrottle(0,1,1); // this broadcasts speed 1(estop) and sets all reminders to speed 1. + // terminate all clients connections + while (!clients.empty()) { + // pop_back() should invoke destructor which does stop() + // on the underlying TCP connction + clients.pop_back(); + } + // stop server + if (server != NULL) { + server->stop(); + server->close(); + server->end(); + DIAG(F("server stop, close, end")); + } + // terminate MDNS anouncement + mdns_service_remove_all(); + mdns_free(); + // stop WiFi + WiFi.disconnect(true); + wifiUp = false; +} + bool WifiESP::setup(const char *SSid, const char *password, const char *hostname, @@ -136,8 +163,10 @@ bool WifiESP::setup(const char *SSid, const bool forceAP) { bool havePassword = true; bool haveSSID = true; - bool wifiUp = false; +// bool wifiUp = false; uint8_t tries = 40; + if (wifiUp) + teardown(); //#ifdef SERIAL_BT_COMMANDS //return false; diff --git a/WifiESP32.h b/WifiESP32.h index ec2f560..58cceca 100644 --- a/WifiESP32.h +++ b/WifiESP32.h @@ -22,6 +22,7 @@ #ifndef WifiESP32_h #define WifiESP32_h +#include #include "FSH.h" class WifiESP @@ -36,6 +37,9 @@ public: const bool forceAP); static void loop(); private: + static void teardown(); + static bool wifiUp; + static WiFiServer *server; }; #endif //WifiESP8266_h #endif //ESP8266