repeat message down a chain, adding to the payload at each repeating device

Dependencies:   sx12xx_hal

radio chip selection

Radio chip driver is not included, because options are available.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
if you're using SX1280, then import sx1280 driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.

/media/uploads/dudmuck/chain.png

network architecture

  • UNIT 0x00 transmitting only device: mandatory.
  • UNIT 0x01: repeating device
  • Uni-directional network: Each unit can only receive message from UNIT_ID - 1 (previous unit)
  • UINT n receiving only device LAST_UNIT: mandatory; prints payload onto UART.

configuration

Each device in the network is uniquely identified by:

  • UNIT_ID: ID byte designating address of this device.
  • UNIT_LAST: If defined, this device prints payload onto serial port instead of re-transmitting payload.

All devices in network must be configured identically with the following:

  • TX_INTERVAL_US: how often to take measurement and send to UNIT_ID+1 (time of complete cycle).
  • MAX_TX_LENGTH: Maximum size of payload, in bytes. Payload is sent in fragments when exceeds this value; aka size of each fragment.
  • TXRX_PADDING_US : Time allotted for RX-TX turnaround and CPU overhead
  • MAX_TX_ATTEMPTS: Count of transmit retries permitted
  • SPREADING_FACTOR LoRa configuration of datarate
  • CF_MHZ : Operating radio frequency


Duration of retry interval is auto-calculated from LoRa modem configuration (bandwidth/sf) and MAX_TX_LENGTH.
Take care that TX_INTERVAL_US value is appropriate relative to total retry interval (interval * MAX_TX_ATTEMPTS)

Revision:
5:62c9ddaa5ea6
Parent:
4:f272bf72893a
--- a/main.cpp	Fri Dec 14 14:41:38 2018 -0800
+++ b/main.cpp	Mon Sep 16 11:18:01 2019 -0700
@@ -55,7 +55,7 @@
     #endif /* TARGET_FF_MORPHO */
 #endif /* !TARGET_DISCO_L072CZ_LRWAN1 */
 
-uint8_t forward[255];
+uint8_t forward_buf[255];
 uint8_t forwardLen;
 uint8_t forwardLenTransmitted;
 uint8_t forwardLenAckd;
@@ -68,7 +68,9 @@
 
 enum _state_ {
     /* 0 */ STATE_NONE = 0,
+#if (UNIT_ID != 0x00)
     /* 1 */ STATE_GET_REQ,
+#endif /* UNIT_ID != 0x00 */
 #ifndef UNIT_LAST
     /* 2 */ STATE_ACK_WAITING,
     /* 3 */ STATE_TX_FORWARD,
@@ -81,7 +83,9 @@
 
     switch (s) {
         case STATE_NONE: str = "NONE"; break;
+#if (UNIT_ID != 0x00)
         case STATE_GET_REQ: str = "GET_REQ"; break;
+#endif /* UNIT_ID != 0x00 */
 #ifndef UNIT_LAST
         case STATE_ACK_WAITING: str = "ACK_WAITING"; break;
         case STATE_TX_FORWARD: str = "TX_FORWARD"; break;
@@ -104,12 +108,13 @@
 } pkt_flags_t;
 
 volatile struct _f_ {
-    uint8_t _sleep_                     : 1;   // 0
+    uint8_t unused                      : 1;   // 0
     uint8_t mbedTImeout_forwarderStarted: 1;   // 1
     uint8_t run                         : 1;   // 2
+    uint8_t svc                         : 1;   // 3
 #ifndef UNIT_LAST
-    uint8_t sample                      : 1;   // 3
-    uint8_t fwd                         : 1;   // 4
+    uint8_t sample                      : 1;   // 4
+    uint8_t fwd                         : 1;   // 5
 #endif /* UNIT_LAST */
 } flags;
 
@@ -146,7 +151,7 @@
     unsigned n;
 
     for (n = 0; n < forwardLen; n += sizeof(message_t)) {
-        const message_t* m = (message_t*)&forward[n];
+        const message_t* m = (message_t*)&forward_buf[n];
 
         pc.printf("unit %02x: %02x, %u\r\n", m->unit_id, m->flags, m->sample);
     }
@@ -158,7 +163,7 @@
 volatile unsigned retryInterval_us;
 volatile us_timestamp_t rxStartAt;
 
-
+#if (UNIT_ID != 0x00)
 void setupNext()
 {
     state = STATE_GET_REQ;
@@ -167,13 +172,10 @@
     pc.printf("->GET_REQ ");
 
     if (measuredInterval > 0) {
-        flags._sleep_ = 1;
         Radio::Sleep();
         pc.printf("SLEEP mi:%llu ", measuredInterval);
         measuredInterval = 0; // single use
     } else {
-        flags._sleep_ = 0;
-
         Radio::Rx(0);
 
         rxStartAt = 0;  // starting of continuous rx not used
@@ -184,8 +186,9 @@
         pc.printf("RX ");
     }
 
-    memset(forward, 0xff, EXPECTED_LENGTH);
+    memset(forward_buf, 0xff, EXPECTED_LENGTH);
 }
+#endif /* UNIT_ID != 0x00 */
 
 LowPowerTimeout mbedTImeout_forwarder;
 
@@ -208,9 +211,7 @@
     if (++f.bits.attempt >= MAX_TX_ATTEMPTS) {
         pc.printf(" lastTry");
         tickerRetry.detach();
-#if (UNIT_ID == 0x00)
-        flags._sleep_ = 1;
-#else
+#if (UNIT_ID != 0x00)
         setupNext();
 #endif /* UNIT_ID != 0x00 */
         pc.printf("\r\n");
@@ -234,6 +235,7 @@
 volatile uint16_t samples[N_SMP];
 #endif
 
+#if (UNIT_ID != 0x00)
 uint8_t _tx_forward()
 {
     unsigned fwdLen;
@@ -259,7 +261,7 @@
     forwardLenTransmitted = forwardLenAckd;
     added = 0;
     while ((txCurs + sizeof(message_t)) < stop && added < toSendLen) {
-        memcpy(Radio::radio.tx_buf + txCurs, forward + forwardLenTransmitted, sizeof(message_t));
+        memcpy(Radio::radio.tx_buf + txCurs, forward_buf + forwardLenTransmitted, sizeof(message_t));
         forwardLenTransmitted += sizeof(message_t);
         txCurs += sizeof(message_t);
         added += sizeof(message_t);
@@ -288,7 +290,6 @@
 
     Radio::Send(txCurs, 0, 0, 0);
     state = STATE_ACK_WAITING;
-    flags._sleep_ = 0;
 
     return txCurs;
 } // .._tx_forward()
@@ -314,10 +315,11 @@
     flags.mbedTImeout_forwarderStarted = 0;
 
     dur = Radio::lora_toa_us(txlen);
-    pc.printf("\e[7mtx_forward_cb %d", now - prevFwdStart - TX_INTERVAL_US);
+    pc.printf("\e[7mtx_forward_cb %lld", now - prevFwdStart - TX_INTERVAL_US);
     pc.printf(" dur%u\e[0m\r\n", dur);
     prevFwdStart = now;
 }
+#endif /* UNIT_ID != 0x00 */
 
 void sample_ticker_cb()
 {
@@ -345,7 +347,6 @@
 
     Radio::Rx(0);
     rxStartAt = Radio::lpt.read_us();
-    flags._sleep_ = 0;
 
     us = (MAX_TX_ATTEMPTS * retryInterval_us) + (MAX_TX_ATTEMPTS * TXRX_PADDING_US);
 
@@ -368,12 +369,15 @@
 
 void rxDoneCB(uint8_t size, float rssi, float snr)
 {
+#if (UNIT_ID != 0x00)
     pkt_flags_t f;
+    us_timestamp_t rxIrqAt = Radio::irqAt;
+#endif /* UNIT_ID != 0x00 */
     char str[32];
-    us_timestamp_t rxIrqAt = Radio::irqAt;
 
     stateToString(state, str);
     pc.printf("\e[33mrxDoneCB() %u rssi:%.1fdBm snr:%.1fdB %s ID:%02x\e[0m ", size, rssi, snr, str, Radio::radio.rx_buf[0]);
+#if (UNIT_ID != 0x00)
     if (state == STATE_GET_REQ) {
         uint8_t len;
         unsigned c, rxc;
@@ -428,7 +432,7 @@
 
         if (prevFrag != f.bits.fragNum) {
             len = size - 4; // -4: header ... crc
-            memcpy(forward + forwardLen, Radio::radio.rx_buf+2, len);
+            memcpy(forward_buf + forwardLen, Radio::radio.rx_buf+2, len);
             forwardLen += len;
 
             prevFrag = f.bits.fragNum;
@@ -439,7 +443,7 @@
             if (rxStartAt == 0) {
                 pc.printf("\e[7m");
             }
-            pc.printf("lastRxIrqAt:%u measuredInterval:%llu ", lastRxIrqAt, measuredInterval);
+            pc.printf("lastRxIrqAt:%llu measuredInterval:%llu ", lastRxIrqAt, measuredInterval);
             if (lastRxIrqAt != 0) {
                 us_timestamp_t thisMeas;
                 int err_;
@@ -451,7 +455,7 @@
                 else
                     abserr = thisMeas - TX_INTERVAL_US;
 
-                pc.printf(" this:%llu err_:%d ", thisMeas, err_);
+                pc.printf(" this:%llu AO:%u, err_:%d ", thisMeas, attemptOffset, err_);
                 if (abserr < MEASURED_MAX_ERR) {
                     int rxPrecedency = 0;
                     unsigned sinceRxDone, _us_;
@@ -497,8 +501,10 @@
         } // ..if (f.bits.fragNum == 0)
 
     } // ..if (state == STATE_GET_REQ)
+    else 
+#endif /* UNIT_ID != 0x00 */
 #ifndef UNIT_LAST
-    else if (state == STATE_ACK_WAITING) {
+    if (state == STATE_ACK_WAITING) {
 
         if (Radio::radio.rx_buf[0] == UNIT_ID+1) {
             pkt_flags_t f;
@@ -510,7 +516,6 @@
                 pc.printf("ackOk-last ");
 #if (UNIT_ID == 0x00)
                 pc.printf("->SLEEP ");
-                flags._sleep_ = 1;
                 Radio::Sleep();
 #else
                 setupNext();
@@ -528,6 +533,15 @@
     }
 #endif /* UNIT_LAST */
 
+    {
+        mbed_stats_cpu_t stats;
+        mbed_stats_cpu_get(&stats);
+        printf("canDeep:%u ", sleep_manager_can_deep_sleep());
+        printf("Uptime: %llu ", stats.uptime / 1000);
+        printf("Sleep time: %llu ", stats.sleep_time / 1000);
+        printf("Deep Sleep: %llu\r\n", stats.deep_sleep_time / 1000);
+    }
+
     pc.printf("\r\n");
 } // ..rxDoneCB()
 
@@ -568,8 +582,17 @@
     Radio::Send(txCurs, 0, 0, 0);
     txStartAt = Radio::lpt.read_us();
     state = STATE_ACK_WAITING;
+
+    {
+        mbed_stats_cpu_t stats;
+        mbed_stats_cpu_get(&stats);
+        pc.printf("canDeep:%u ", sleep_manager_can_deep_sleep());
+        pc.printf("Uptime: %llu ", stats.uptime / 1000);
+        pc.printf("Sleep time: %llu ", stats.sleep_time / 1000);
+        pc.printf("Deep Sleep: %llu ", stats.deep_sleep_time / 1000);
+    }
+
     pc.printf("tx_ticker_cb:%u\r\n", mptr->sample);
-    flags._sleep_ = 0;
 }
 #endif /* UNIT_ID == 0x00 */
 
@@ -643,7 +666,7 @@
             printf("UNIT_ID:%02x ", UNIT_ID);
             printf(" measuredInterval:%llu\r\n", measuredInterval);
             stateToString(state, str);
-            printf("_sleep_:%u %s\r\n", flags._sleep_, str);
+            printf(" %s\r\n", str);
             break;
         case 'r':
             flags.run ^= 1;
@@ -655,14 +678,28 @@
                 mbedTImeout_forwarder.detach();
                 mbedTimeout_nextRx.detach();
 
-                flags._sleep_ = 1;
                 Radio::Sleep();
             }
             break;
     } // ..switch (ch)
 }
 
-RadioEvents_t rev = { 0 };
+void radio_irq_topHalf()
+{
+    flags.svc = 1;
+}
+
+const RadioEvents_t rev = {
+    /* DioPin_top_half */     radio_irq_topHalf,
+    /* TxDone_topHalf */    NULL,//txDoneCBth,
+    /* TxDone_botHalf */    txDoneCB,
+    /* TxTimeout  */        NULL,
+    /* RxDone  */           rxDoneCB,
+    /* RxTimeout  */        NULL,
+    /* RxError  */          NULL,
+    /* FhssChangeChannel  */NULL,
+    /* CadDone  */          NULL
+};
 
 int main()
 {
@@ -670,8 +707,6 @@
     pc.baud(115200);
     pc.printf("\r\nreset\r\n");
 
-    rev.TxDone_botHalf = txDoneCB;
-    rev.RxDone = rxDoneCB;
     Radio::Init(&rev);
 
     Radio::Standby();
@@ -695,7 +730,6 @@
 #endif
     pc.printf("UNIT_ID:%02x retryInterval_us:%u\r\n", UNIT_ID, retryInterval_us);
 
-    flags._sleep_ = 0;
     state = STATE_NONE;
 
 #if (UNIT_ID == 0x00) && !defined(UNIT_LAST)
@@ -712,8 +746,10 @@
     measuredIntervalSaved = 0;
 #endif /* UNIT_ID != 0x00 */
 
+    /*
     if (sleep_manager_can_deep_sleep())
         sleep_manager_lock_deep_sleep();    // prevent deep sleep
+        */
 
     for (;;) {
         if (pc.readable()) {
@@ -729,7 +765,11 @@
 #endif
             print_radio_chip();
             if (flags.fwd) {
+#if (UNIT_ID == 0x00)
+                pc.printf("\e[31mID00-fwd\e[0m\r\n");
+#else
                 _tx_forward();
+#endif /* UNIT_ID != 0x00 */
                 flags.fwd = 0;
             }
 
@@ -737,10 +777,12 @@
         }
 #endif /* UNIT_LAST */
 
-        if (flags._sleep_ == 0) {
+        sleep_manager_sleep_auto();;
+
+        if (flags.svc) {
             Radio::service();
-        } else
-            sleep_manager_sleep_auto();;
+            flags.svc = 0;
+        }
 
     } // ..for (;;)
 }