diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 26923c77..76792909 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -91,7 +91,7 @@ struct RepeaterStats { uint32_t total_up_time_secs; uint32_t n_sent_flood, n_sent_direct; uint32_t n_recv_flood, n_recv_direct; - uint16_t n_full_events; + uint16_t err_events; // was 'n_full_events' int16_t last_snr; // x 4 uint16_t n_direct_dups, n_flood_dups; }; @@ -195,7 +195,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { stats.n_sent_direct = getNumSentDirect(); stats.n_recv_flood = getNumRecvFlood(); stats.n_recv_direct = getNumRecvDirect(); - stats.n_full_events = getNumFullEvents(); + stats.err_events = _err_flags; stats.last_snr = (int16_t)(radio_driver.getLastSNR() * 4); stats.n_direct_dups = ((SimpleMeshTables *)getTables())->getNumDirectDups(); stats.n_flood_dups = ((SimpleMeshTables *)getTables())->getNumFloodDups(); diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index a5d78e3c..756be6d5 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -138,7 +138,7 @@ struct ServerStats { uint32_t total_up_time_secs; uint32_t n_sent_flood, n_sent_direct; uint32_t n_recv_flood, n_recv_direct; - uint16_t n_full_events; + uint16_t err_events; // was 'n_full_events' int16_t last_snr; // x 4 uint16_t n_direct_dups, n_flood_dups; uint16_t n_posted, n_post_push; @@ -301,7 +301,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { stats.n_sent_direct = getNumSentDirect(); stats.n_recv_flood = getNumRecvFlood(); stats.n_recv_direct = getNumRecvDirect(); - stats.n_full_events = getNumFullEvents(); + stats.err_events = _err_flags; stats.last_snr = (int16_t)(radio_driver.getLastSNR() * 4); stats.n_direct_dups = ((SimpleMeshTables *)getTables())->getNumDirectDups(); stats.n_flood_dups = ((SimpleMeshTables *)getTables())->getNumFloodDups(); diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index 2b4c4675..5a09c171 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -13,7 +13,7 @@ namespace mesh { void Dispatcher::begin() { n_sent_flood = n_sent_direct = 0; n_recv_flood = n_recv_direct = 0; - n_full_events = 0; + _err_flags = 0; _radio->begin(); } @@ -34,6 +34,18 @@ uint32_t Dispatcher::getCADFailMaxDuration() const { } void Dispatcher::loop() { + // check for radio 'stuck' in mode other than Rx + bool is_recv = _radio->isInRecvMode(); + if (is_recv != prev_isrecv_mode) { + prev_isrecv_mode = is_recv; + if (!is_recv) { + radio_nonrx_start = _ms->getMillis(); + } + } + if (!is_recv && _ms->getMillis() - radio_nonrx_start > 8000) { // radio has not been in Rx mode for 8 seconds! + _err_flags |= ERR_EVENT_STARTRX_TIMEOUT; + } + if (outbound) { // waiting for outbound send to be completed if (_radio->isSendComplete()) { long t = _ms->getMillis() - outbound_start; @@ -199,6 +211,8 @@ void Dispatcher::checkSend() { } if (_ms->getMillis() - cad_busy_start > getCADFailMaxDuration()) { + _err_flags |= ERR_EVENT_CAD_TIMEOUT; + MESH_DEBUG_PRINTLN("%s Dispatcher::checkSend(): CAD busy max duration reached!", getLogDateTime()); // channel activity has gone on too long... (Radio might be in a bad state) // force the pending transmit below... @@ -264,7 +278,7 @@ void Dispatcher::checkSend() { Packet* Dispatcher::obtainNewPacket() { auto pkt = _mgr->allocNew(); // TODO: zero out all fields if (pkt == NULL) { - n_full_events++; + _err_flags |= ERR_EVENT_FULL; } else { pkt->payload_len = pkt->path_len = 0; pkt->_snr = 0; diff --git a/src/Dispatcher.h b/src/Dispatcher.h index 96db4fc5..01dd76bc 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -56,6 +56,8 @@ public: */ virtual void onSendFinished() = 0; + virtual bool isInRecvMode() const = 0; + /** * \returns true if the radio is currently mid-receive of a packet. */ @@ -91,6 +93,10 @@ typedef uint32_t DispatcherAction; #define ACTION_RETRANSMIT(pri) (((uint32_t)1 + (pri))<<24) #define ACTION_RETRANSMIT_DELAYED(pri, _delay) ((((uint32_t)1 + (pri))<<24) | (_delay)) +#define ERR_EVENT_FULL (1 << 0) +#define ERR_EVENT_CAD_TIMEOUT (1 << 1) +#define ERR_EVENT_STARTRX_TIMEOUT (1 << 2) + /** * \brief The low-level task that manages detecting incoming Packets, and the queueing * and scheduling of outbound Packets. @@ -100,9 +106,10 @@ class Dispatcher { unsigned long outbound_expiry, outbound_start, total_air_time; unsigned long next_tx_time; unsigned long cad_busy_start; + unsigned long radio_nonrx_start; + bool prev_isrecv_mode; uint32_t n_sent_flood, n_sent_direct; uint32_t n_recv_flood, n_recv_direct; - uint32_t n_full_events; void processRecvPacket(Packet* pkt); @@ -110,12 +117,16 @@ protected: PacketManager* _mgr; Radio* _radio; MillisecondClock* _ms; + uint16_t _err_flags; Dispatcher(Radio& radio, MillisecondClock& ms, PacketManager& mgr) : _radio(&radio), _ms(&ms), _mgr(&mgr) { outbound = NULL; total_air_time = 0; next_tx_time = 0; cad_busy_start = 0; + _err_flags = 0; + radio_nonrx_start = 0; + prev_isrecv_mode = true; } virtual DispatcherAction onRecvPacket(Packet* pkt) = 0; @@ -145,7 +156,6 @@ public: uint32_t getNumSentDirect() const { return n_sent_direct; } uint32_t getNumRecvFlood() const { return n_recv_flood; } uint32_t getNumRecvDirect() const { return n_recv_direct; } - uint32_t getNumFullEvents() const { return n_full_events; } // helper methods bool millisHasNowPassed(unsigned long timestamp) const; diff --git a/src/helpers/RadioLibWrappers.cpp b/src/helpers/RadioLibWrappers.cpp index fa678431..39fb340e 100644 --- a/src/helpers/RadioLibWrappers.cpp +++ b/src/helpers/RadioLibWrappers.cpp @@ -44,6 +44,10 @@ void RadioLibWrapper::startRecv() { } } +bool RadioLibWrapper::isInRecvMode() const { + return (state & ~STATE_INT_READY) == STATE_RX; +} + int RadioLibWrapper::recvRaw(uint8_t* bytes, int sz) { if (state & STATE_INT_READY) { int len = _radio->getPacketLength(); diff --git a/src/helpers/RadioLibWrappers.h b/src/helpers/RadioLibWrappers.h index a97987ef..8dc03e28 100644 --- a/src/helpers/RadioLibWrappers.h +++ b/src/helpers/RadioLibWrappers.h @@ -22,6 +22,7 @@ public: bool startSendRaw(const uint8_t* bytes, int len) override; bool isSendComplete() override; void onSendFinished() override; + bool isInRecvMode() const override; uint32_t getPacketsRecv() const { return n_recv; } uint32_t getPacketsSent() const { return n_sent; } diff --git a/src/helpers/esp32/ESPNOWRadio.cpp b/src/helpers/esp32/ESPNOWRadio.cpp index a48a3430..ced19f91 100644 --- a/src/helpers/esp32/ESPNOWRadio.cpp +++ b/src/helpers/esp32/ESPNOWRadio.cpp @@ -5,7 +5,7 @@ static uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static esp_now_peer_info_t peerInfo; -static bool is_send_complete = false; +static volatile bool is_send_complete = false; static esp_err_t last_send_result; static uint8_t rx_buf[256]; static uint8_t last_rx_len = 0; @@ -44,6 +44,8 @@ void ESPNOWRadio::init() { peerInfo.channel = 0; peerInfo.encrypt = false; + is_send_complete = true; + // Add peer if (esp_now_add_peer(&peerInfo) == ESP_OK) { ESPNOW_DEBUG_PRINTLN("init success"); @@ -86,6 +88,11 @@ bool ESPNOWRadio::isSendComplete() { return is_send_complete; } void ESPNOWRadio::onSendFinished() { + is_send_complete = true; +} + +bool ESPNOWRadio::isInRecvMode() const { + return is_send_complete; // if NO send in progress, then we're in Rx mode } float ESPNOWRadio::getLastRSSI() const { return 0; } diff --git a/src/helpers/esp32/ESPNOWRadio.h b/src/helpers/esp32/ESPNOWRadio.h index 4b33df58..5d4ff583 100644 --- a/src/helpers/esp32/ESPNOWRadio.h +++ b/src/helpers/esp32/ESPNOWRadio.h @@ -15,6 +15,7 @@ public: bool startSendRaw(const uint8_t* bytes, int len) override; bool isSendComplete() override; void onSendFinished() override; + bool isInRecvMode() const override; uint32_t getPacketsRecv() const { return n_recv; } uint32_t getPacketsSent() const { return n_sent; }