diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index b7854b2cf..e7355db29 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -25,7 +25,7 @@ void consolePrintf(const char *format, ...) #endif } -SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port) +SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), concurrency::OSThread("SerialConsole") { assert(!console); console = this; @@ -46,6 +46,10 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port) emitRebooted(); } +int32_t SerialConsole::runOnce() +{ + return runOncePart(); +} // For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages bool SerialConsole::checkIsConnected() diff --git a/src/SerialConsole.h b/src/SerialConsole.h index e7b8af34f..d1f2abac8 100644 --- a/src/SerialConsole.h +++ b/src/SerialConsole.h @@ -6,7 +6,7 @@ * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). */ -class SerialConsole : public StreamAPI, public RedirectablePrint +class SerialConsole : public StreamAPI, public RedirectablePrint, private concurrency::OSThread { public: SerialConsole(); @@ -24,6 +24,8 @@ class SerialConsole : public StreamAPI, public RedirectablePrint return RedirectablePrint::write(c); } + virtual int32_t runOnce() override; + protected: /// Check the current underlying physical link to see if the client is currently connected diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp index 0b959ddcb..d1213ac54 100644 --- a/src/mesh/StreamAPI.cpp +++ b/src/mesh/StreamAPI.cpp @@ -6,7 +6,7 @@ #define START2 0xc3 #define HEADER_LEN 4 -int32_t StreamAPI::runOnce() +int32_t StreamAPI::runOncePart() { auto result = readStream(); writeStream(); diff --git a/src/mesh/StreamAPI.h b/src/mesh/StreamAPI.h index 0f36ecb06..3196e96f8 100644 --- a/src/mesh/StreamAPI.h +++ b/src/mesh/StreamAPI.h @@ -28,7 +28,7 @@ valid utf8 encoding. This makes it a bit easier to start a device outputting reg after it has received a valid packet from the PC, turn off unencoded debug printing and switch to this packet encoding. */ -class StreamAPI : public PhoneAPI, protected concurrency::OSThread +class StreamAPI : public PhoneAPI { /** * The stream we read/write from @@ -42,13 +42,13 @@ class StreamAPI : public PhoneAPI, protected concurrency::OSThread uint32_t lastRxMsec = 0; public: - StreamAPI(Stream *_stream) : concurrency::OSThread("StreamAPI"), stream(_stream) {} + StreamAPI(Stream *_stream) : stream(_stream) {} /** * Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the * phone. */ - virtual int32_t runOnce() override; + virtual int32_t runOncePart(); private: /** diff --git a/src/mesh/eth/ethServerAPI.cpp b/src/mesh/eth/ethServerAPI.cpp index bb7dd927d..3b3b6bbc8 100644 --- a/src/mesh/eth/ethServerAPI.cpp +++ b/src/mesh/eth/ethServerAPI.cpp @@ -14,7 +14,7 @@ void initApiServer(int port) } } -ethServerAPI::ethServerAPI(EthernetClient &_client) : StreamAPI(&client), client(_client) +ethServerAPI::ethServerAPI(EthernetClient &_client) : StreamAPI(&client), concurrency::OSThread("ethServerAPI"), client(_client) { DEBUG_MSG("Incoming ethernet connection\n"); } @@ -42,7 +42,7 @@ bool ethServerAPI::checkIsConnected() int32_t ethServerAPI::runOnce() { if (client.connected()) { - return StreamAPI::runOnce(); + return StreamAPI::runOncePart(); } else { DEBUG_MSG("Client dropped connection, suspending API service\n"); enabled = false; // we no longer need to run diff --git a/src/mesh/eth/ethServerAPI.h b/src/mesh/eth/ethServerAPI.h index c92ab2f17..962841c80 100644 --- a/src/mesh/eth/ethServerAPI.h +++ b/src/mesh/eth/ethServerAPI.h @@ -7,7 +7,7 @@ * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). */ -class ethServerAPI : public StreamAPI +class ethServerAPI : public StreamAPI, private concurrency::OSThread { private: EthernetClient client; diff --git a/src/mesh/wifi/WiFiServerAPI.cpp b/src/mesh/wifi/WiFiServerAPI.cpp index 34a15f71b..78936176b 100644 --- a/src/mesh/wifi/WiFiServerAPI.cpp +++ b/src/mesh/wifi/WiFiServerAPI.cpp @@ -14,7 +14,7 @@ void initApiServer(int port) } } -WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client) +WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), concurrency::OSThread("WiFiServerAPI"), client(_client) { DEBUG_MSG("Incoming wifi connection\n"); } @@ -42,7 +42,7 @@ bool WiFiServerAPI::checkIsConnected() int32_t WiFiServerAPI::runOnce() { if (client.connected()) { - return StreamAPI::runOnce(); + return StreamAPI::runOncePart(); } else { DEBUG_MSG("Client dropped connection, suspending API service\n"); enabled = false; // we no longer need to run diff --git a/src/mesh/wifi/WiFiServerAPI.h b/src/mesh/wifi/WiFiServerAPI.h index 84a23be06..812408818 100644 --- a/src/mesh/wifi/WiFiServerAPI.h +++ b/src/mesh/wifi/WiFiServerAPI.h @@ -7,7 +7,7 @@ * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). */ -class WiFiServerAPI : public StreamAPI +class WiFiServerAPI : public StreamAPI, private concurrency::OSThread { private: WiFiClient client; diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 9978f2487..96a6c0582 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -24,7 +24,7 @@ #endif #if defined(ARCH_ESP32) || defined(ARCH_NRF52) #include "modules/ExternalNotificationModule.h" -#if !defined(TTGO_T_ECHO) +#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2) #include "modules/SerialModule.h" #endif #endif @@ -63,7 +63,7 @@ void setupModules() new DeviceTelemetryModule(); new EnvironmentTelemetryModule(); #endif -#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) +#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2) new SerialModule(); #endif #ifdef ARCH_ESP32 diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 33bae7746..f0374bb41 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -46,20 +46,25 @@ */ +#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2) + #define RXD2 16 #define TXD2 17 #define RX_BUFFER 128 +#define STRING_MAX Constants_DATA_PAYLOAD_LEN #define TIMEOUT 250 #define BAUD 38400 #define ACK 1 +// API: Defaulting to the formerly removed phone_timeout_secs value of 15 minutes +#define SERIAL_CONNECTION_TIMEOUT (15 * 60) * 1000UL + SerialModule *serialModule; SerialModuleRadio *serialModuleRadio; -SerialModule::SerialModule() : concurrency::OSThread("SerialModule") {} +SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("SerialModule") {} -char serialBytes[Constants_DATA_PAYLOAD_LEN]; -size_t serialPayloadSize; +char serialStringChar[Constants_DATA_PAYLOAD_LEN]; SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio") { @@ -80,9 +85,15 @@ SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio") } } +// For the serial2 port we can't really detect if any client is on the other side, so instead just look for recent messages +bool SerialModule::checkIsConnected() +{ + uint32_t now = millis(); + return (now - lastContactMsec) < SERIAL_CONNECTION_TIMEOUT; +} + int32_t SerialModule::runOnce() { -#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2) /* Uncomment the preferences below if you want to use the module without having to configure it from the PythonAPI or WebUI. @@ -178,19 +189,32 @@ int32_t SerialModule::runOnce() firstTime = 0; + // in API mode send rebooted sequence + if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) { + emitRebooted(); + } + } else { - // in NMEA mode send out GGA every 2 seconds, Don't read from Port - if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) { + if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) { + return runOncePart(); + } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) { + // in NMEA mode send out GGA every 2 seconds, Don't read from Port if (millis() - lastNmeaTime > 2000) { lastNmeaTime = millis(); printGGA(outbuf, nodeDB.getNode(myNodeInfo.my_node_num)->position); Serial2.printf("%s", outbuf); } } else { + String serialString; + while (Serial2.available()) { - serialPayloadSize = Serial2.readBytes(serialBytes, Constants_DATA_PAYLOAD_LEN); + serialString = Serial2.readString(); + serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN); + serialModuleRadio->sendPayload(); + + DEBUG_MSG("Received: %s\n", serialStringChar); } } } @@ -201,9 +225,6 @@ int32_t SerialModule::runOnce() return INT32_MAX; } -#else - return INT32_MAX; -#endif } MeshPacket *SerialModuleRadio::allocReply() @@ -221,16 +242,19 @@ void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies) p->want_ack = ACK; - p->decoded.payload.size = serialPayloadSize; // You must specify how many bytes are in the reply - memcpy(p->decoded.payload.bytes, serialBytes, p->decoded.payload.size); + p->decoded.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply + memcpy(p->decoded.payload.bytes, serialStringChar, p->decoded.payload.size); service.sendToMesh(p); } ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp) { -#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2) if (moduleConfig.serial.enabled) { + if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) { + // in API mode we don't care about stuff from radio. + return ProcessMessage::CONTINUE; + } auto &p = mp.decoded; // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", @@ -258,15 +282,13 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp) if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT || moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) { - Serial2.write(p.payload.bytes, p.payload.size); + Serial2.printf("%s", p.payload.bytes); } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG) { NodeInfo *node = nodeDB.getNode(getFrom(&mp)); String sender = (node && node->has_user) ? node->user.short_name : "???"; Serial2.println(); Serial2.printf("%s: %s", sender, p.payload.bytes); Serial2.println(); - } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) { - // TODO this needs to be implemented } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) { // Decode the Payload some more Position scratch; @@ -286,8 +308,6 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp) } else { DEBUG_MSG("Serial Module Disabled\n"); } - -#endif - return ProcessMessage::CONTINUE; // Let others look at this message also if they want } +#endif diff --git a/src/modules/SerialModule.h b/src/modules/SerialModule.h index 0130bbe2d..c853263b6 100644 --- a/src/modules/SerialModule.h +++ b/src/modules/SerialModule.h @@ -8,7 +8,9 @@ #include "Router.h" #include -class SerialModule : private concurrency::OSThread +#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2) + +class SerialModule : public StreamAPI, private concurrency::OSThread { bool firstTime = 1; unsigned long lastNmeaTime = millis(); @@ -19,6 +21,9 @@ class SerialModule : private concurrency::OSThread protected: virtual int32_t runOnce() override; + + /// Check the current underlying physical link to see if the client is currently connected + virtual bool checkIsConnected() override; }; extern SerialModule *serialModule; @@ -65,3 +70,5 @@ class SerialModuleRadio : public MeshModule }; extern SerialModuleRadio *serialModuleRadio; + +#endif