diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp
index ad1cf642a..11534b1ee 100644
--- a/src/SerialConsole.cpp
+++ b/src/SerialConsole.cpp
@@ -6,25 +6,28 @@
#define Port Serial
-SerialConsole console;
+SerialConsole *console;
+
+void consoleInit()
+{
+ new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
+}
void consolePrintf(const char *format, ...)
{
va_list arg;
va_start(arg, format);
- console.vprintf(format, arg);
+ console->vprintf(format, arg);
va_end(arg);
}
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
{
+ assert(!console);
+ console = this;
canWrite = false; // We don't send packets to our port until it has talked to us first
- // setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
-}
+ // setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
-/// Do late init that can't happen at constructor time
-void SerialConsole::init()
-{
Port.begin(SERIAL_BAUD);
StreamAPI::init();
emitRebooted();
@@ -34,14 +37,14 @@ void SerialConsole::init()
* we override this to notice when we've received a protobuf over the serial
* stream. Then we shunt off debug serial output.
*/
-void SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
+bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
{
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
if (!radioConfig.preferences.debug_log_enabled)
setDestination(&noopPrint);
canWrite = true;
- StreamAPI::handleToRadio(buf, len);
+ return StreamAPI::handleToRadio(buf, len);
}
/// Hookable to find out when connection changes
diff --git a/src/SerialConsole.h b/src/SerialConsole.h
index b4f076286..b057c1931 100644
--- a/src/SerialConsole.h
+++ b/src/SerialConsole.h
@@ -11,14 +11,11 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
public:
SerialConsole();
- /// Do late init that can't happen at constructor time
- virtual void init();
-
/**
* we override this to notice when we've received a protobuf over the serial stream. Then we shunt off
* debug serial output.
*/
- virtual void handleToRadio(const uint8_t *buf, size_t len);
+ virtual bool handleToRadio(const uint8_t *buf, size_t len);
virtual size_t write(uint8_t c)
{
@@ -34,5 +31,6 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
// A simple wrapper to allow non class aware code write to the console
void consolePrintf(const char *format, ...);
+void consoleInit();
-extern SerialConsole console;
+extern SerialConsole *console;
diff --git a/src/concurrency/BinarySemaphoreFreeRTOS.h b/src/concurrency/BinarySemaphoreFreeRTOS.h
index b5e488fd2..2883151d8 100644
--- a/src/concurrency/BinarySemaphoreFreeRTOS.h
+++ b/src/concurrency/BinarySemaphoreFreeRTOS.h
@@ -1,6 +1,5 @@
#pragma once
-#include "configuration.h"
#include "../freertosinc.h"
namespace concurrency
@@ -28,4 +27,4 @@ class BinarySemaphoreFreeRTOS
#endif
-}
\ No newline at end of file
+} // namespace concurrency
\ No newline at end of file
diff --git a/src/configuration.h b/src/configuration.h
index 1704ad14a..f0d3a0a53 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -457,7 +457,7 @@ along with this program. If not, see .
#include "SerialConsole.h"
-#define DEBUG_PORT console // Serial debug port
+#define DEBUG_PORT (*console) // Serial debug port
// What platforms should use SEGGER?
#ifdef NRF52_SERIES
diff --git a/src/main.cpp b/src/main.cpp
index 6a4caf330..1621d081f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -177,6 +177,7 @@ class ButtonThread : public OSThread
OneButton userButtonAlt;
#endif
static bool shutdown_on_long_stop;
+
public:
static uint32_t longPressTime;
@@ -250,15 +251,15 @@ class ButtonThread : public OSThread
power->shutdown();
}
#elif NRF52_SERIES
- // Do actual shutdown when button released, otherwise the button release
- // may wake the board immediatedly.
- if (!shutdown_on_long_stop) {
- DEBUG_MSG("Shutdown from long press");
- playBeep();
- ledOff(PIN_LED1);
- ledOff(PIN_LED2);
- shutdown_on_long_stop = true;
- }
+ // Do actual shutdown when button released, otherwise the button release
+ // may wake the board immediatedly.
+ if (!shutdown_on_long_stop) {
+ DEBUG_MSG("Shutdown from long press");
+ playBeep();
+ ledOff(PIN_LED1);
+ ledOff(PIN_LED2);
+ shutdown_on_long_stop = true;
+ }
#endif
} else {
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
@@ -315,9 +316,8 @@ void setup()
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
#endif
-// Debug
#ifdef DEBUG_PORT
- DEBUG_PORT.init(); // Set serial baud rate and init our mesh console
+ consoleInit(); // Set serial baud rate and init our mesh console
#endif
initDeepSleep();
@@ -580,10 +580,6 @@ void loop()
{
// axpDebugOutput.loop();
-#ifdef DEBUG_PORT
- DEBUG_PORT.loop(); // Send/receive protobufs over the serial port
-#endif
-
// heap_caps_check_integrity_all(true); // FIXME - disable this expensive check
#ifndef NO_ESP32
diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp
index d542b21cf..e270b5a2c 100644
--- a/src/mesh/MeshService.cpp
+++ b/src/mesh/MeshService.cpp
@@ -114,7 +114,7 @@ bool MeshService::reloadConfig()
void MeshService::reloadOwner()
{
assert(nodeInfoPlugin);
- if(nodeInfoPlugin)
+ if (nodeInfoPlugin)
nodeInfoPlugin->sendOurNodeInfo();
nodeDB.saveToDisk();
}
@@ -172,13 +172,12 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
assert(node);
if (node->has_position) {
- if(positionPlugin) {
+ if (positionPlugin) {
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
positionPlugin->sendOurPosition(dest, wantReplies);
}
- }
- else {
- if(nodeInfoPlugin) {
+ } else {
+ if (nodeInfoPlugin) {
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
}
diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h
index 0f2e772b3..7d22a3004 100644
--- a/src/mesh/MeshService.h
+++ b/src/mesh/MeshService.h
@@ -84,13 +84,12 @@ class MeshService
NodeInfo *refreshMyNodeInfo();
private:
-
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
/// returns 0 to allow futher processing
int onGPSChanged(const meshtastic::GPSStatus *arg);
- /// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it needs
- /// to keep the packet around it makes a copy
+ /// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
+ /// needs to keep the packet around it makes a copy
int handleFromRadio(const MeshPacket *p);
friend class RoutingPlugin;
};
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index b50381e70..3eaa60674 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -1,10 +1,10 @@
#include "PhoneAPI.h"
+#include "Channels.h"
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "RadioInterface.h"
-#include "Channels.h"
#include
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
@@ -22,16 +22,18 @@ void PhoneAPI::init()
observe(&service.fromNumChanged);
}
-PhoneAPI::~PhoneAPI() {
+PhoneAPI::~PhoneAPI()
+{
close();
}
-void PhoneAPI::close() {
+void PhoneAPI::close()
+{
unobserve();
state = STATE_SEND_NOTHING;
bool oldConnected = isConnected;
isConnected = false;
- if(oldConnected != isConnected)
+ if (oldConnected != isConnected)
onConnectionChanged(isConnected);
}
@@ -49,7 +51,7 @@ void PhoneAPI::checkConnectionTimeout()
/**
* Handle a ToRadio protobuf
*/
-void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
+bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
{
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep
lastContactMsec = millis();
@@ -62,12 +64,9 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
switch (toRadioScratch.which_payloadVariant) {
- case ToRadio_packet_tag: {
- MeshPacket &p = toRadioScratch.packet;
- printPacket("PACKET FROM PHONE", &p);
- service.handleToRadio(p);
- break;
- }
+ case ToRadio_packet_tag:
+ return handleToRadioPacket(toRadioScratch.packet);
+
case ToRadio_want_config_id_tag:
config_nonce = toRadioScratch.want_config_id;
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
@@ -86,6 +85,8 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
} else {
DEBUG_MSG("Error: ignoring malformed toradio\n");
}
+
+ return false;
}
/**
@@ -127,7 +128,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.my_info = myNodeInfo;
state = STATE_SEND_NODEINFO;
- service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
+ service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
break;
case STATE_SEND_NODEINFO: {
@@ -226,7 +227,13 @@ bool PhoneAPI::available()
/**
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
*/
-void PhoneAPI::handleToRadioPacket(MeshPacket *p) {}
+bool PhoneAPI::handleToRadioPacket(MeshPacket &p)
+{
+ printPacket("PACKET FROM PHONE", &p);
+ service.handleToRadio(p);
+
+ return true;
+}
/// If the mesh service tells us fromNum has changed, tell the phone
int PhoneAPI::onNotify(uint32_t newValue)
diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h
index 6d03d2c80..dc7de3e18 100644
--- a/src/mesh/PhoneAPI.h
+++ b/src/mesh/PhoneAPI.h
@@ -67,8 +67,9 @@ class PhoneAPI
/**
* Handle a ToRadio protobuf
+ * @return true true if a packet was queued for sending (so that caller can yield)
*/
- virtual void handleToRadio(const uint8_t *buf, size_t len);
+ virtual bool handleToRadio(const uint8_t *buf, size_t len);
/**
* Get the next packet we want to send to the phone
@@ -93,7 +94,7 @@ class PhoneAPI
/// Hookable to find out when connection changes
virtual void onConnectionChanged(bool connected) {}
- /// If we haven't heard from the other side in a while then say not connected
+ /// If we haven't heard from the other side in a while then say not connected
void checkConnectionTimeout();
/**
@@ -103,9 +104,10 @@ class PhoneAPI
private:
/**
- * Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
+ * Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it
+ * @return true true if a packet was queued for sending
*/
- void handleToRadioPacket(MeshPacket *p);
+ bool handleToRadioPacket(MeshPacket &p);
/// If the mesh service tells us fromNum has changed, tell the phone
virtual int onNotify(uint32_t newValue);
diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp
index a5e36d463..2bc82b084 100644
--- a/src/mesh/StreamAPI.cpp
+++ b/src/mesh/StreamAPI.cpp
@@ -5,48 +5,62 @@
#define START2 0xc3
#define HEADER_LEN 4
-void StreamAPI::loop()
+int32_t StreamAPI::runOnce()
{
+ auto result = readStream();
writeStream();
- readStream();
checkConnectionTimeout();
+ return result;
}
/**
* Read any rx chars from the link and call handleToRadio
*/
-void StreamAPI::readStream()
+int32_t StreamAPI::readStream()
{
- while (stream->available()) { // Currently we never want to block
- uint8_t c = stream->read();
+ uint32_t now = millis();
+ if (!stream->available()) {
+ // Nothing available this time, if the computer has talked to us recently, poll often, otherwise let CPU sleep a long time
+ bool recentRx = (now - lastRxMsec) < 2000;
+ return recentRx ? 5 : 250;
+ } else {
+ while (stream->available()) { // Currently we never want to block
+ uint8_t c = stream->read();
- // Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
- size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
+ // Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
+ size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
- rxBuf[ptr] = c; // store all bytes (including framing)
+ rxBuf[ptr] = c; // store all bytes (including framing)
- if (ptr == 0) { // looking for START1
- if (c != START1)
- rxPtr = 0; // failed to find framing
- } else if (ptr == 1) { // looking for START2
- if (c != START2)
- rxPtr = 0; // failed to find framing
- } else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
- uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
+ if (ptr == 0) { // looking for START1
+ if (c != START1)
+ rxPtr = 0; // failed to find framing
+ } else if (ptr == 1) { // looking for START2
+ if (c != START2)
+ rxPtr = 0; // failed to find framing
+ } else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
+ uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
- if (ptr == HEADER_LEN) {
- // we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
- // protobuf also)
- if (len > MAX_TO_FROM_RADIO_SIZE)
- rxPtr = 0; // length is bogus, restart search for framing
- }
+ if (ptr == HEADER_LEN) {
+ // we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
+ // protobuf also)
+ if (len > MAX_TO_FROM_RADIO_SIZE)
+ rxPtr = 0; // length is bogus, restart search for framing
+ }
- if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
- // If we didn't just fail the packet and we now have the right # of bytes, parse it
- handleToRadio(rxBuf + HEADER_LEN, len);
- rxPtr = 0; // start over again
+ if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
+ rxPtr = 0; // start over again on the next packet
+
+ // If we didn't just fail the packet and we now have the right # of bytes, parse it
+ if (handleToRadio(rxBuf + HEADER_LEN, len))
+ return 0; // we want to be called again ASAP because we still have more work to do
+ }
}
}
+
+ // we had packets available this time, so assume we might have them next time also
+ lastRxMsec = now;
+ return 0;
}
}
@@ -71,7 +85,7 @@ void StreamAPI::writeStream()
void StreamAPI::emitTxBuffer(size_t len)
{
if (len != 0) {
- DEBUG_MSG("emit tx %d\n", len);
+ // DEBUG_MSG("emit tx %d\n", len);
txBuf[0] = START1;
txBuf[1] = START2;
txBuf[2] = (len >> 8) & 0xff;
@@ -93,6 +107,6 @@ void StreamAPI::emitRebooted()
fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag;
fromRadioScratch.rebooted = true;
- DEBUG_MSG("Emitting reboot packet for serial shell\n");
+ // DEBUG_MSG("Emitting reboot packet for serial shell\n");
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
}
\ No newline at end of file
diff --git a/src/mesh/StreamAPI.h b/src/mesh/StreamAPI.h
index ed0a5fbd4..6180a95d8 100644
--- a/src/mesh/StreamAPI.h
+++ b/src/mesh/StreamAPI.h
@@ -2,6 +2,7 @@
#include "PhoneAPI.h"
#include "Stream.h"
+#include "concurrency/OSThread.h"
// A To/FromRadio packet + our 32 bit header
#define MAX_STREAM_BUF_SIZE (MAX_TO_FROM_RADIO_SIZE + sizeof(uint32_t))
@@ -27,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
+class StreamAPI : public PhoneAPI, protected concurrency::OSThread
{
/**
* The stream we read/write from
@@ -37,21 +38,23 @@ class StreamAPI : public PhoneAPI
uint8_t rxBuf[MAX_STREAM_BUF_SIZE];
size_t rxPtr = 0;
+ /// time of last rx, used, to slow down our polling if we haven't heard from anyone
+ uint32_t lastRxMsec = 0;
+
public:
- StreamAPI(Stream *_stream) : stream(_stream) {}
+ StreamAPI(Stream *_stream) : concurrency::OSThread("StreamAPI"), stream(_stream) {}
/**
* Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the
* phone.
- * FIXME, to support better power behavior instead move to a thread and block on serial reads.
*/
- void loop();
+ virtual int32_t runOnce();
private:
/**
* Read any rx chars from the link and call handleToRadio
*/
- void readStream();
+ int32_t readStream();
/**
* call getFromRadio() and deliver encapsulated packets to the Stream
@@ -63,7 +66,7 @@ class StreamAPI : public PhoneAPI
* Send a FromRadio.rebooted = true packet to the phone
*/
void emitRebooted();
-
+
/**
* Send the current txBuffer over our stream
*/
diff --git a/src/mesh/wifi/WiFiServerAPI.cpp b/src/mesh/wifi/WiFiServerAPI.cpp
index 37183975e..c0be8bc4a 100644
--- a/src/mesh/wifi/WiFiServerAPI.cpp
+++ b/src/mesh/wifi/WiFiServerAPI.cpp
@@ -40,18 +40,20 @@ void WiFiServerAPI::onConnectionChanged(bool connected)
}
/// override close to also shutdown the TCP link
-void WiFiServerAPI::close() {
+void WiFiServerAPI::close()
+{
client.stop(); // drop tcp connection
StreamAPI::close();
}
-bool WiFiServerAPI::loop()
+int32_t WiFiServerAPI::runOnce()
{
if (client.connected()) {
- StreamAPI::loop();
- return true;
+ return StreamAPI::runOnce();
} else {
- return false;
+ DEBUG_MSG("Client dropped connection, suspending API service\n");
+ enabled = false; // we no longer need to run
+ return 0;
}
}
@@ -78,18 +80,5 @@ int32_t WiFiServerPort::runOnce()
openAPI = new WiFiServerAPI(client);
}
- if (openAPI) {
- // Allow idle processing so the API can read from its incoming stream
- if(!openAPI->loop()) {
- // If our API link was up, shut it down
-
- DEBUG_MSG("Client dropped connection, closing API client\n");
- // Note: we can't call delete here because this object includes other state
- // besides the stream API. Instead kill it later when we start a new instance
- delete openAPI;
- openAPI = NULL;
- }
- return 0; // run fast while our API server is running
- } else
- return 100; // only check occasionally for incoming connections
+ return 100; // only check occasionally for incoming connections
}
\ No newline at end of file
diff --git a/src/mesh/wifi/WiFiServerAPI.h b/src/mesh/wifi/WiFiServerAPI.h
index 46e2fad93..96cfb2bb0 100644
--- a/src/mesh/wifi/WiFiServerAPI.h
+++ b/src/mesh/wifi/WiFiServerAPI.h
@@ -1,7 +1,6 @@
#pragma once
#include "StreamAPI.h"
-#include "concurrency/OSThread.h"
#include
/**
@@ -18,15 +17,14 @@ class WiFiServerAPI : public StreamAPI
virtual ~WiFiServerAPI();
- /// @return true if we want to keep running, or false if we are ready to be destroyed
- virtual bool loop(); // Check for dropped client connections
-
/// override close to also shutdown the TCP link
virtual void close();
protected:
/// Hookable to find out when connection changes
virtual void onConnectionChanged(bool connected);
+
+ virtual int32_t runOnce(); // Check for dropped client connections
};
/**