Merge pull request #2060 from meshtastic/protobuf-serial

ProtobufAPI in SerialModule
This commit is contained in:
Thomas Göttgens 2022-12-22 20:29:01 +01:00 committed by GitHub
commit adb8d773d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 67 additions and 34 deletions

View File

@ -25,7 +25,7 @@ void consolePrintf(const char *format, ...)
#endif #endif
} }
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port) SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), concurrency::OSThread("SerialConsole")
{ {
assert(!console); assert(!console);
console = this; console = this;
@ -46,6 +46,10 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
emitRebooted(); 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 // 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() bool SerialConsole::checkIsConnected()

View File

@ -6,7 +6,7 @@
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * 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). * (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: public:
SerialConsole(); SerialConsole();
@ -24,6 +24,8 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
return RedirectablePrint::write(c); return RedirectablePrint::write(c);
} }
virtual int32_t runOnce() override;
protected: protected:
/// Check the current underlying physical link to see if the client is currently connected /// Check the current underlying physical link to see if the client is currently connected

View File

@ -6,7 +6,7 @@
#define START2 0xc3 #define START2 0xc3
#define HEADER_LEN 4 #define HEADER_LEN 4
int32_t StreamAPI::runOnce() int32_t StreamAPI::runOncePart()
{ {
auto result = readStream(); auto result = readStream();
writeStream(); writeStream();

View File

@ -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. 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 * The stream we read/write from
@ -42,13 +42,13 @@ class StreamAPI : public PhoneAPI, protected concurrency::OSThread
uint32_t lastRxMsec = 0; uint32_t lastRxMsec = 0;
public: 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 * Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the
* phone. * phone.
*/ */
virtual int32_t runOnce() override; virtual int32_t runOncePart();
private: private:
/** /**

View File

@ -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"); DEBUG_MSG("Incoming ethernet connection\n");
} }
@ -42,7 +42,7 @@ bool ethServerAPI::checkIsConnected()
int32_t ethServerAPI::runOnce() int32_t ethServerAPI::runOnce()
{ {
if (client.connected()) { if (client.connected()) {
return StreamAPI::runOnce(); return StreamAPI::runOncePart();
} else { } else {
DEBUG_MSG("Client dropped connection, suspending API service\n"); DEBUG_MSG("Client dropped connection, suspending API service\n");
enabled = false; // we no longer need to run enabled = false; // we no longer need to run

View File

@ -7,7 +7,7 @@
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * 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). * (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: private:
EthernetClient client; EthernetClient client;

View File

@ -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"); DEBUG_MSG("Incoming wifi connection\n");
} }
@ -42,7 +42,7 @@ bool WiFiServerAPI::checkIsConnected()
int32_t WiFiServerAPI::runOnce() int32_t WiFiServerAPI::runOnce()
{ {
if (client.connected()) { if (client.connected()) {
return StreamAPI::runOnce(); return StreamAPI::runOncePart();
} else { } else {
DEBUG_MSG("Client dropped connection, suspending API service\n"); DEBUG_MSG("Client dropped connection, suspending API service\n");
enabled = false; // we no longer need to run enabled = false; // we no longer need to run

View File

@ -7,7 +7,7 @@
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * 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). * (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: private:
WiFiClient client; WiFiClient client;

View File

@ -24,7 +24,7 @@
#endif #endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) #if defined(ARCH_ESP32) || defined(ARCH_NRF52)
#include "modules/ExternalNotificationModule.h" #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" #include "modules/SerialModule.h"
#endif #endif
#endif #endif
@ -63,7 +63,7 @@ void setupModules()
new DeviceTelemetryModule(); new DeviceTelemetryModule();
new EnvironmentTelemetryModule(); new EnvironmentTelemetryModule();
#endif #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(); new SerialModule();
#endif #endif
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32

View File

@ -46,20 +46,25 @@
*/ */
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
#define RXD2 16 #define RXD2 16
#define TXD2 17 #define TXD2 17
#define RX_BUFFER 128 #define RX_BUFFER 128
#define STRING_MAX Constants_DATA_PAYLOAD_LEN
#define TIMEOUT 250 #define TIMEOUT 250
#define BAUD 38400 #define BAUD 38400
#define ACK 1 #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; SerialModule *serialModule;
SerialModuleRadio *serialModuleRadio; SerialModuleRadio *serialModuleRadio;
SerialModule::SerialModule() : concurrency::OSThread("SerialModule") {} SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("SerialModule") {}
char serialBytes[Constants_DATA_PAYLOAD_LEN]; char serialStringChar[Constants_DATA_PAYLOAD_LEN];
size_t serialPayloadSize;
SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio") 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() 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 Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI. without having to configure it from the PythonAPI or WebUI.
@ -178,19 +189,32 @@ int32_t SerialModule::runOnce()
firstTime = 0; firstTime = 0;
// in API mode send rebooted sequence
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
emitRebooted();
}
} else { } else {
// in NMEA mode send out GGA every 2 seconds, Don't read from Port if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) { 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) { if (millis() - lastNmeaTime > 2000) {
lastNmeaTime = millis(); lastNmeaTime = millis();
printGGA(outbuf, nodeDB.getNode(myNodeInfo.my_node_num)->position); printGGA(outbuf, nodeDB.getNode(myNodeInfo.my_node_num)->position);
Serial2.printf("%s", outbuf); Serial2.printf("%s", outbuf);
} }
} else { } else {
String serialString;
while (Serial2.available()) { while (Serial2.available()) {
serialPayloadSize = Serial2.readBytes(serialBytes, Constants_DATA_PAYLOAD_LEN); serialString = Serial2.readString();
serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN);
serialModuleRadio->sendPayload(); serialModuleRadio->sendPayload();
DEBUG_MSG("Received: %s\n", serialStringChar);
} }
} }
} }
@ -201,9 +225,6 @@ int32_t SerialModule::runOnce()
return INT32_MAX; return INT32_MAX;
} }
#else
return INT32_MAX;
#endif
} }
MeshPacket *SerialModuleRadio::allocReply() MeshPacket *SerialModuleRadio::allocReply()
@ -221,16 +242,19 @@ void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
p->want_ack = ACK; p->want_ack = ACK;
p->decoded.payload.size = serialPayloadSize; // You must specify how many bytes are in the reply p->decoded.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply
memcpy(p->decoded.payload.bytes, serialBytes, p->decoded.payload.size); memcpy(p->decoded.payload.bytes, serialStringChar, p->decoded.payload.size);
service.sendToMesh(p); service.sendToMesh(p);
} }
ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp) 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.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; auto &p = mp.decoded;
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", // 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 || if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) { 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) { } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG) {
NodeInfo *node = nodeDB.getNode(getFrom(&mp)); NodeInfo *node = nodeDB.getNode(getFrom(&mp));
String sender = (node && node->has_user) ? node->user.short_name : "???"; String sender = (node && node->has_user) ? node->user.short_name : "???";
Serial2.println(); Serial2.println();
Serial2.printf("%s: %s", sender, p.payload.bytes); Serial2.printf("%s: %s", sender, p.payload.bytes);
Serial2.println(); 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) { } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
// Decode the Payload some more // Decode the Payload some more
Position scratch; Position scratch;
@ -286,8 +308,6 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
} else { } else {
DEBUG_MSG("Serial Module Disabled\n"); DEBUG_MSG("Serial Module Disabled\n");
} }
#endif
return ProcessMessage::CONTINUE; // Let others look at this message also if they want return ProcessMessage::CONTINUE; // Let others look at this message also if they want
} }
#endif

View File

@ -8,7 +8,9 @@
#include "Router.h" #include "Router.h"
#include <functional> #include <functional>
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; bool firstTime = 1;
unsigned long lastNmeaTime = millis(); unsigned long lastNmeaTime = millis();
@ -19,6 +21,9 @@ class SerialModule : private concurrency::OSThread
protected: protected:
virtual int32_t runOnce() override; 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; extern SerialModule *serialModule;
@ -65,3 +70,5 @@ class SerialModuleRadio : public MeshModule
}; };
extern SerialModuleRadio *serialModuleRadio; extern SerialModuleRadio *serialModuleRadio;
#endif