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:
2:534be88a25dc
Parent:
1:7dbf0926e146
Child:
3:a78a70af3403
--- a/main.cpp	Thu Jul 05 17:43:35 2018 -0700
+++ b/main.cpp	Mon Jul 16 11:20:20 2018 -0700
@@ -10,7 +10,7 @@
     uint16_t sample;
 
     #ifdef N_SMP
-    uint16_t samples[N_SMP]; 
+    uint16_t samples[N_SMP];
     #endif
 } message_t;
 
@@ -19,7 +19,15 @@
 #define TXRX_PADDING_US             10000
 #define MAX_TX_ATTEMPTS             4
 #define SPREADING_FACTOR            9
-#define CF_MHZ                      917.6
+#ifdef SX128x_H
+    #define CF_MHZ                      2487.0
+    #define BW_KHZ                      200
+    #define TX_DBM                      12
+#else
+    #define CF_MHZ                      917.6
+    #define BW_KHZ                      500
+    #define TX_DBM                      17
+#endif
 
 #define EXPECTED_LENGTH     (UNIT_ID * sizeof(message_t))
 //#define MEASURED_MAX_ERR        (TX_INTERVAL_US / 4000)     // +/-100ppm allowance
@@ -98,6 +106,7 @@
     uint8_t _sleep_        : 1;   // 0
     uint8_t mbedTImeout_forwarderStarted: 1;   // 1
     uint8_t run                         : 1;   // 2
+    uint8_t sample                      : 1;   // 3
 } flags;
 
 
@@ -152,6 +161,7 @@
     forwardLen = 0;
     prevFrag = -1;
     pc.printf("->GET_REQ ");
+
     if (measuredInterval > 0) {
         flags._sleep_ = 1;
         Radio::Sleep();
@@ -159,10 +169,12 @@
         measuredInterval = 0; // single use
     } else {
         flags._sleep_ = 0;
+
         Radio::Rx(0);
 
         rxStartAt = 0;  // starting of continuous rx not used
 
+        flags.sample = 1;
         pc.printf("RX ");
     }
 
@@ -262,8 +274,6 @@
     Radio::radio.tx_buf[txCurs++] = c >> 8;
     Radio::radio.tx_buf[txCurs++] = c;
 
-    /*Radio::set_tx_dbm(17);
-        Radio::PrintStatus();*/
     Radio::Send(txCurs, 0, 0, 0);
     state = STATE_ACK_WAITING;
     flags._sleep_ = 0;
@@ -322,6 +332,8 @@
     us = (MAX_TX_ATTEMPTS * retryInterval_us) + (MAX_TX_ATTEMPTS * TXRX_PADDING_US);
 
     pc.printf("nextRxStartCB for %uus\r\n", us);
+
+    flags.sample = 1;
 }
 
 
@@ -329,7 +341,7 @@
 {
     char str[32];
 
-    Radio::Rx(0);
+    Radio::Rx(0);   // receive ack
     stateToString(state, str);
     pc.printf("%s:txDone->Rx\r\n", str);
 }
@@ -346,12 +358,12 @@
         uint8_t len;
         unsigned c, rxc;
         if (Radio::radio.rx_buf[0] != UNIT_ID-1) {
-            pc.printf("\r\n");
+            pc.printf(" (not %02x)\r\n", UNIT_ID-1);
             return;
         }
         if (size < 4) {
             /* minimum: header + crc */
-            pc.printf("\r\n");
+            pc.printf(" (size<4)\r\n");
             return;
         }
         f.octet = Radio::radio.rx_buf[1];
@@ -390,8 +402,6 @@
         }
 
         Radio::radio.tx_buf[0] = UNIT_ID;   // OK, send ACK
-        /*YYY Radio::set_tx_dbm(17);
-        Radio::PrintStatus();*/
         Radio::Send(1, 0, 0, 0);
 
 
@@ -499,8 +509,20 @@
     pc.printf("\r\n");
 } // ..rxDoneCB()
 
+void sample_ticker_cb()
+{
+    flags.sample = 1;
+}
+
+
+uint16_t sample;
+
+#ifdef N_SMP
+uint16_t samples[N_SMP];
+#endif
+
 #if (UNIT_ID == 0x00) && !defined(UNIT_LAST)
-LowPowerTicker      lpTicker;
+LowPowerTicker      sampleTicker, txTicker;
 
 void tx_ticker_cb(void) {
     unsigned c;
@@ -522,10 +544,10 @@
     mptr = (message_t*)(Radio::radio.tx_buf + txCurs);
     mptr->unit_id = UNIT_ID;
     mptr->flags = 0x00;
-    mptr->sample = ain.read_u16();
+    mptr->sample = sample;
 #ifdef N_SMP
     for (c = 0; c < N_SMP; c++)
-        mptr->samples[c] = ain.read_u16();
+        mptr->samples[c] = samples[c];
 #endif
     txCurs += sizeof(message_t);
 
@@ -541,6 +563,55 @@
 }
 #endif /* UNIT_ID == 0x00 */
 
+#ifdef SX128x_H
+void
+print_radio_chip()
+{
+    uint8_t buf[6];
+    unsigned khz = 0;
+    LoRaPktPar0_t LoRaPktPar0;
+    LoRaPktPar1_t LoRaPktPar1;
+    status_t st;
+
+    Radio::radio.xfer(OPCODE_GET_IRQ_STATUS, 0, 3, buf);
+    st.octet = buf[0];
+    printf("mode:%u cmdStatus:%u irq:%02x %02x ", st.bits.chipMode, st.bits.cmdStatus, buf[1], buf[2]);
+
+    LoRaPktPar0.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR0, 1);
+    switch (LoRaPktPar0.bits.modem_bw) {
+        case 2: khz = 200; break;
+        case 3: khz = 400; break;
+        case 4: khz = 800; break;
+        case 5: khz = 1600; break;
+    }
+    printf("read:%uKHz sf%u\r\n", khz, LoRaPktPar0.bits.modem_sf);
+
+    printf("paylen%u ", (uint8_t)Radio::radio.readReg(REG_ADDR_LORA_TX_PAYLOAD_LENGTH, 1));
+    LoRaPktPar1.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR1, 1);
+    printf("cr%u ", LoRaPktPar1.bits.coding_rate);
+    if (LoRaPktPar1.bits.rxinvert_iq)
+        printf("std ");
+    else
+        printf("inv ");
+    if (LoRaPktPar1.bits.implicit_header)
+        printf("im");
+    else
+        printf("ex");
+    printf("plicit\r\n");
+}
+#elif defined(SX127x_H) /* ...SX128x_H */
+
+void
+print_radio_chip()
+{
+}
+#elif defined(SX126x_H) /* ...SX127x_H */
+
+void
+print_radio_chip()
+{
+}
+#endif
 
 void uart_rx()
 {
@@ -563,6 +634,9 @@
             printf(" measuredInterval:%llu\r\n", measuredInterval);
             stateToString(state, str);
             printf("_sleep_:%u %s\r\n", flags._sleep_, str);
+#ifdef SX128x_H
+            print_sx1280();
+#endif
             break;
         case 'r':
             flags.run ^= 1;
@@ -593,11 +667,12 @@
     rev.RxDone = rxDoneCB;
     Radio::Init(&rev);
 
-    Radio::SetChannel(CF_MHZ * 1000000);
-    Radio::LoRaModemConfig(500, SPREADING_FACTOR, 1);
+    Radio::Standby();
+    Radio::LoRaModemConfig(BW_KHZ, SPREADING_FACTOR, 1);
     Radio::LoRaPacketConfig(8, false, true, false);  // preambleLen, fixLen, crcOn, invIQ
+    Radio::SetChannel(CF_MHZ * 1000000);
 
-    Radio::set_tx_dbm(17);
+    Radio::set_tx_dbm(TX_DBM);
 
     /* max TX length + turnaround + ACK length */
     retryInterval_us = Radio::lora_toa_us(MAX_TX_LENGTH) + TXRX_PADDING_US + Radio::lora_toa_us(1);
@@ -610,7 +685,9 @@
     state = STATE_NONE;
 
 #if (UNIT_ID == 0x00) && !defined(UNIT_LAST)
-    lpTicker.attach_us(tx_ticker_cb, TX_INTERVAL_US);
+    sampleTicker.attach_us(sample_ticker_cb, TX_INTERVAL_US);
+    wait_us(50000);
+    txTicker.attach_us(tx_ticker_cb, TX_INTERVAL_US);
 #else
     //Radio::PrintStatus();
 
@@ -629,6 +706,17 @@
             uart_rx();
         }
 
+        if (flags.sample) {
+            sample = ain.read_u16();
+#ifdef N_SMP
+            for (c = 0; c < N_SMP; c++)
+                samples[c] = ain.read_u16();
+#endif
+            print_radio_chip();
+
+            flags.sample = 0;
+        }
+
         if (flags._sleep_ == 0) {
             Radio::service();
         } else