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)

Committer:
Wayne Roberts
Date:
Wed Jun 13 17:49:58 2018 -0700
Revision:
0:d88677306896
Child:
1:7dbf0926e146
initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:d88677306896 1 #include "radio.h"
Wayne Roberts 0:d88677306896 2
Wayne Roberts 0:d88677306896 3 #define UNIT_ID 0x01 /* 0x00: first unit */
Wayne Roberts 0:d88677306896 4 //#define UNIT_LAST
Wayne Roberts 0:d88677306896 5
Wayne Roberts 0:d88677306896 6 // test large sample, large pkt size #define N_SMP 10
Wayne Roberts 0:d88677306896 7 typedef struct __attribute__((__packed__)) msg {
Wayne Roberts 0:d88677306896 8 uint8_t unit_id;
Wayne Roberts 0:d88677306896 9 uint8_t flags;
Wayne Roberts 0:d88677306896 10 uint16_t sample;
Wayne Roberts 0:d88677306896 11
Wayne Roberts 0:d88677306896 12 #ifdef N_SMP
Wayne Roberts 0:d88677306896 13 uint16_t samples[N_SMP];
Wayne Roberts 0:d88677306896 14 #endif
Wayne Roberts 0:d88677306896 15 } message_t;
Wayne Roberts 0:d88677306896 16
Wayne Roberts 0:d88677306896 17 #define TX_INTERVAL_US 5000000
Wayne Roberts 0:d88677306896 18 #define MAX_TX_LENGTH 64
Wayne Roberts 0:d88677306896 19 #define TXRX_PADDING_US 10000
Wayne Roberts 0:d88677306896 20 #define MAX_TX_ATTEMPTS 4
Wayne Roberts 0:d88677306896 21 #define SPREADING_FACTOR 9
Wayne Roberts 0:d88677306896 22 #define CF_MHZ 917.6
Wayne Roberts 0:d88677306896 23
Wayne Roberts 0:d88677306896 24 #define EXPECTED_LENGTH (UNIT_ID * sizeof(message_t))
Wayne Roberts 0:d88677306896 25 //#define MEASURED_MAX_ERR (TX_INTERVAL_US / 4000) // +/-100ppm allowance
Wayne Roberts 0:d88677306896 26 #define MEASURED_MAX_ERR (TX_INTERVAL_US / 300) // +/-Xppm allowance
Wayne Roberts 0:d88677306896 27
Wayne Roberts 0:d88677306896 28 #if defined(SX127x_H)
Wayne Roberts 0:d88677306896 29 #define RX_STARTUP_US 1500
Wayne Roberts 0:d88677306896 30 #elif defined(SX126x_H)
Wayne Roberts 0:d88677306896 31 #define RX_STARTUP_US 1000
Wayne Roberts 0:d88677306896 32 #endif
Wayne Roberts 0:d88677306896 33 unsigned rxStartup_us = RX_STARTUP_US;
Wayne Roberts 0:d88677306896 34
Wayne Roberts 0:d88677306896 35 RawSerial pc(USBTX, USBRX);
Wayne Roberts 0:d88677306896 36
Wayne Roberts 0:d88677306896 37 #ifdef TARGET_DISCO_L072CZ_LRWAN1
Wayne Roberts 0:d88677306896 38 AnalogIn ain(A0);
Wayne Roberts 0:d88677306896 39 #else
Wayne Roberts 0:d88677306896 40 #ifdef TARGET_FF_MORPHO
Wayne Roberts 0:d88677306896 41 AnalogIn ain(PC_4); // pin unused by arduino shields
Wayne Roberts 0:d88677306896 42 #endif /* TARGET_FF_MORPHO */
Wayne Roberts 0:d88677306896 43 #endif /* !TARGET_DISCO_L072CZ_LRWAN1 */
Wayne Roberts 0:d88677306896 44
Wayne Roberts 0:d88677306896 45 uint8_t forward[255];
Wayne Roberts 0:d88677306896 46 uint8_t forwardLen;
Wayne Roberts 0:d88677306896 47 uint8_t forwardLenTransmitted;
Wayne Roberts 0:d88677306896 48 uint8_t forwardLenAckd;
Wayne Roberts 0:d88677306896 49 int prevFrag;
Wayne Roberts 0:d88677306896 50 volatile us_timestamp_t forwardedAt;
Wayne Roberts 0:d88677306896 51
Wayne Roberts 0:d88677306896 52 volatile us_timestamp_t lastRxIrqAt;
Wayne Roberts 0:d88677306896 53 volatile us_timestamp_t measuredInterval, measuredIntervalSaved;
Wayne Roberts 0:d88677306896 54
Wayne Roberts 0:d88677306896 55
Wayne Roberts 0:d88677306896 56 enum _state_ {
Wayne Roberts 0:d88677306896 57 /* 0 */ STATE_NONE = 0,
Wayne Roberts 0:d88677306896 58 /* 1 */ STATE_GET_REQ,
Wayne Roberts 0:d88677306896 59 #ifndef UNIT_LAST
Wayne Roberts 0:d88677306896 60 /* 2 */ STATE_ACK_WAITING,
Wayne Roberts 0:d88677306896 61 /* 3 */ STATE_TX_FORWARD,
Wayne Roberts 0:d88677306896 62 #endif /* UNIT_LAST */
Wayne Roberts 0:d88677306896 63 } state;
Wayne Roberts 0:d88677306896 64
Wayne Roberts 0:d88677306896 65 void stateToString(enum _state_ s, char* out)
Wayne Roberts 0:d88677306896 66 {
Wayne Roberts 0:d88677306896 67 const char* str;
Wayne Roberts 0:d88677306896 68
Wayne Roberts 0:d88677306896 69 switch (s) {
Wayne Roberts 0:d88677306896 70 case STATE_NONE: str = "NONE"; break;
Wayne Roberts 0:d88677306896 71 case STATE_GET_REQ: str = "GET_REQ"; break;
Wayne Roberts 0:d88677306896 72 #ifndef UNIT_LAST
Wayne Roberts 0:d88677306896 73 case STATE_ACK_WAITING: str = "ACK_WAITING"; break;
Wayne Roberts 0:d88677306896 74 case STATE_TX_FORWARD: str = "TX_FORWARD"; break;
Wayne Roberts 0:d88677306896 75 #endif /* UNIT_LAST */
Wayne Roberts 0:d88677306896 76 default:
Wayne Roberts 0:d88677306896 77 sprintf(out, "??%u??", s);
Wayne Roberts 0:d88677306896 78 return;
Wayne Roberts 0:d88677306896 79 }
Wayne Roberts 0:d88677306896 80
Wayne Roberts 0:d88677306896 81 strcpy(out, str);
Wayne Roberts 0:d88677306896 82 }
Wayne Roberts 0:d88677306896 83
Wayne Roberts 0:d88677306896 84 typedef union {
Wayne Roberts 0:d88677306896 85 struct {
Wayne Roberts 0:d88677306896 86 uint8_t attempt : 3; // 0,1,2
Wayne Roberts 0:d88677306896 87 uint8_t fragNum : 4; // 3,4,5,6
Wayne Roberts 0:d88677306896 88 uint8_t fragLast : 1; // 7
Wayne Roberts 0:d88677306896 89 } bits;
Wayne Roberts 0:d88677306896 90 uint8_t octet;
Wayne Roberts 0:d88677306896 91 } pkt_flags_t;
Wayne Roberts 0:d88677306896 92
Wayne Roberts 0:d88677306896 93 volatile struct _f_ {
Wayne Roberts 0:d88677306896 94 uint8_t _sleep_ : 1; // 0
Wayne Roberts 0:d88677306896 95 uint8_t mbedTImeout_forwarderStarted: 1; // 1
Wayne Roberts 0:d88677306896 96 uint8_t run : 1; // 2
Wayne Roberts 0:d88677306896 97 } flags;
Wayne Roberts 0:d88677306896 98
Wayne Roberts 0:d88677306896 99
Wayne Roberts 0:d88677306896 100 static uint16_t crc16( uint8_t *buffer, uint16_t length )
Wayne Roberts 0:d88677306896 101 {
Wayne Roberts 0:d88677306896 102 uint16_t i;
Wayne Roberts 0:d88677306896 103 // The CRC calculation follows CCITT
Wayne Roberts 0:d88677306896 104 const uint16_t polynom = 0x1021;
Wayne Roberts 0:d88677306896 105 // CRC initial value
Wayne Roberts 0:d88677306896 106 uint16_t crc = 0x0000;
Wayne Roberts 0:d88677306896 107
Wayne Roberts 0:d88677306896 108 if( buffer == NULL )
Wayne Roberts 0:d88677306896 109 {
Wayne Roberts 0:d88677306896 110 return 0;
Wayne Roberts 0:d88677306896 111 }
Wayne Roberts 0:d88677306896 112
Wayne Roberts 0:d88677306896 113 for( i = 0; i < length; ++i )
Wayne Roberts 0:d88677306896 114 {
Wayne Roberts 0:d88677306896 115 uint16_t j;
Wayne Roberts 0:d88677306896 116 crc ^= ( uint16_t ) buffer[i] << 8;
Wayne Roberts 0:d88677306896 117 for( j = 0; j < 8; ++j )
Wayne Roberts 0:d88677306896 118 {
Wayne Roberts 0:d88677306896 119 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
Wayne Roberts 0:d88677306896 120 }
Wayne Roberts 0:d88677306896 121 }
Wayne Roberts 0:d88677306896 122
Wayne Roberts 0:d88677306896 123 return crc;
Wayne Roberts 0:d88677306896 124 }
Wayne Roberts 0:d88677306896 125
Wayne Roberts 0:d88677306896 126 #ifdef UNIT_LAST
Wayne Roberts 0:d88677306896 127 void print_payload()
Wayne Roberts 0:d88677306896 128 {
Wayne Roberts 0:d88677306896 129 unsigned n;
Wayne Roberts 0:d88677306896 130
Wayne Roberts 0:d88677306896 131 for (n = 0; n < forwardLen; n += sizeof(message_t)) {
Wayne Roberts 0:d88677306896 132 const message_t* m = (message_t*)&forward[n];
Wayne Roberts 0:d88677306896 133
Wayne Roberts 0:d88677306896 134 pc.printf("unit %02x: %02x, %u\r\n", m->unit_id, m->flags, m->sample);
Wayne Roberts 0:d88677306896 135 }
Wayne Roberts 0:d88677306896 136
Wayne Roberts 0:d88677306896 137 }
Wayne Roberts 0:d88677306896 138 #endif /* UNIT_LAST */
Wayne Roberts 0:d88677306896 139
Wayne Roberts 0:d88677306896 140 LowPowerTimeout mbedTimeout_nextRx;
Wayne Roberts 0:d88677306896 141 volatile unsigned retryInterval_us;
Wayne Roberts 0:d88677306896 142 volatile us_timestamp_t rxStartAt;
Wayne Roberts 0:d88677306896 143
Wayne Roberts 0:d88677306896 144
Wayne Roberts 0:d88677306896 145 void setupNext()
Wayne Roberts 0:d88677306896 146 {
Wayne Roberts 0:d88677306896 147 state = STATE_GET_REQ;
Wayne Roberts 0:d88677306896 148 forwardLen = 0;
Wayne Roberts 0:d88677306896 149 prevFrag = -1;
Wayne Roberts 0:d88677306896 150 pc.printf("->GET_REQ ");
Wayne Roberts 0:d88677306896 151 if (measuredInterval > 0) {
Wayne Roberts 0:d88677306896 152 flags._sleep_ = 1;
Wayne Roberts 0:d88677306896 153 Radio::Sleep();
Wayne Roberts 0:d88677306896 154 pc.printf("SLEEP mi:%llu ", measuredInterval);
Wayne Roberts 0:d88677306896 155 measuredInterval = 0; // single use
Wayne Roberts 0:d88677306896 156 } else {
Wayne Roberts 0:d88677306896 157 flags._sleep_ = 0;
Wayne Roberts 0:d88677306896 158 Radio::Rx();
Wayne Roberts 0:d88677306896 159
Wayne Roberts 0:d88677306896 160 rxStartAt = 0; // starting of continuous rx not used
Wayne Roberts 0:d88677306896 161
Wayne Roberts 0:d88677306896 162 pc.printf("RX ");
Wayne Roberts 0:d88677306896 163 }
Wayne Roberts 0:d88677306896 164
Wayne Roberts 0:d88677306896 165 memset(forward, 0xff, EXPECTED_LENGTH);
Wayne Roberts 0:d88677306896 166 }
Wayne Roberts 0:d88677306896 167
Wayne Roberts 0:d88677306896 168 LowPowerTimeout mbedTImeout_forwarder;
Wayne Roberts 0:d88677306896 169
Wayne Roberts 0:d88677306896 170 #ifndef UNIT_LAST
Wayne Roberts 0:d88677306896 171 volatile uint8_t txCurs;
Wayne Roberts 0:d88677306896 172
Wayne Roberts 0:d88677306896 173 LowPowerTicker tickerRetry;
Wayne Roberts 0:d88677306896 174
Wayne Roberts 0:d88677306896 175 void retry_cb()
Wayne Roberts 0:d88677306896 176 {
Wayne Roberts 0:d88677306896 177 unsigned c;
Wayne Roberts 0:d88677306896 178 pkt_flags_t f;
Wayne Roberts 0:d88677306896 179
Wayne Roberts 0:d88677306896 180 f.octet = Radio::radio.tx_buf[1];
Wayne Roberts 0:d88677306896 181 pc.printf("attempt%u", f.bits.attempt);
Wayne Roberts 0:d88677306896 182 if (++f.bits.attempt >= MAX_TX_ATTEMPTS) {
Wayne Roberts 0:d88677306896 183 pc.printf(" lastTry");
Wayne Roberts 0:d88677306896 184 tickerRetry.detach();
Wayne Roberts 0:d88677306896 185 #if (UNIT_ID != 0x00)
Wayne Roberts 0:d88677306896 186 setupNext();
Wayne Roberts 0:d88677306896 187 #endif /* UNIT_ID != 0x00 */
Wayne Roberts 0:d88677306896 188 pc.printf("\r\n");
Wayne Roberts 0:d88677306896 189 return;
Wayne Roberts 0:d88677306896 190 }
Wayne Roberts 0:d88677306896 191 pc.printf("->%u\r\n", f.bits.attempt);
Wayne Roberts 0:d88677306896 192 Radio::radio.tx_buf[1] = f.octet;
Wayne Roberts 0:d88677306896 193
Wayne Roberts 0:d88677306896 194 c = crc16(Radio::radio.tx_buf, txCurs-2);
Wayne Roberts 0:d88677306896 195 Radio::radio.tx_buf[txCurs-2] = c >> 8;
Wayne Roberts 0:d88677306896 196 Radio::radio.tx_buf[txCurs-1] = c;
Wayne Roberts 0:d88677306896 197
Wayne Roberts 0:d88677306896 198 Radio::Send(txCurs, 0, 0, 0);
Wayne Roberts 0:d88677306896 199 state = STATE_ACK_WAITING;
Wayne Roberts 0:d88677306896 200 }
Wayne Roberts 0:d88677306896 201
Wayne Roberts 0:d88677306896 202 uint8_t _tx_forward()
Wayne Roberts 0:d88677306896 203 {
Wayne Roberts 0:d88677306896 204 unsigned fwdLen;
Wayne Roberts 0:d88677306896 205 unsigned c;
Wayne Roberts 0:d88677306896 206 uint8_t added, avail, toSendLen, stop = MAX_TX_LENGTH-2;
Wayne Roberts 0:d88677306896 207 pkt_flags_t f;
Wayne Roberts 0:d88677306896 208
Wayne Roberts 0:d88677306896 209 tickerRetry.attach_us(retry_cb, retryInterval_us);
Wayne Roberts 0:d88677306896 210
Wayne Roberts 0:d88677306896 211 if (forwardLen < EXPECTED_LENGTH) {
Wayne Roberts 0:d88677306896 212 pc.printf("\e[31mmissing %u bytes\e[0m ", EXPECTED_LENGTH - forwardLen);
Wayne Roberts 0:d88677306896 213 fwdLen = EXPECTED_LENGTH;
Wayne Roberts 0:d88677306896 214 }
Wayne Roberts 0:d88677306896 215 fwdLen = forwardLen;
Wayne Roberts 0:d88677306896 216
Wayne Roberts 0:d88677306896 217 f.octet = Radio::radio.tx_buf[1];
Wayne Roberts 0:d88677306896 218
Wayne Roberts 0:d88677306896 219 txCurs = 0;
Wayne Roberts 0:d88677306896 220 Radio::radio.tx_buf[txCurs++] = UNIT_ID;
Wayne Roberts 0:d88677306896 221 txCurs++; // placeholder for flags to be added at end
Wayne Roberts 0:d88677306896 222
Wayne Roberts 0:d88677306896 223 toSendLen = fwdLen - forwardLenAckd;
Wayne Roberts 0:d88677306896 224 forwardLenTransmitted = forwardLenAckd;
Wayne Roberts 0:d88677306896 225 added = 0;
Wayne Roberts 0:d88677306896 226 while ((txCurs + sizeof(message_t)) < stop && added < toSendLen) {
Wayne Roberts 0:d88677306896 227 memcpy(Radio::radio.tx_buf + txCurs, forward + forwardLenTransmitted, sizeof(message_t));
Wayne Roberts 0:d88677306896 228 forwardLenTransmitted += sizeof(message_t);
Wayne Roberts 0:d88677306896 229 txCurs += sizeof(message_t);
Wayne Roberts 0:d88677306896 230 added += sizeof(message_t);
Wayne Roberts 0:d88677306896 231 }
Wayne Roberts 0:d88677306896 232
Wayne Roberts 0:d88677306896 233 avail = stop - txCurs;
Wayne Roberts 0:d88677306896 234 if (avail >= sizeof(message_t)) {
Wayne Roberts 0:d88677306896 235 message_t* mptr = (message_t*)(Radio::radio.tx_buf + txCurs);
Wayne Roberts 0:d88677306896 236 mptr->unit_id = UNIT_ID;
Wayne Roberts 0:d88677306896 237 mptr->flags = 0x00;
Wayne Roberts 0:d88677306896 238 mptr->sample = ain.read_u16();
Wayne Roberts 0:d88677306896 239 #ifdef N_SMP
Wayne Roberts 0:d88677306896 240 for (c = 0; c < N_SMP; c++)
Wayne Roberts 0:d88677306896 241 mptr->samples[c] = ain.read_u16();
Wayne Roberts 0:d88677306896 242 #endif
Wayne Roberts 0:d88677306896 243 txCurs += sizeof(message_t);
Wayne Roberts 0:d88677306896 244
Wayne Roberts 0:d88677306896 245 f.bits.fragLast = 1;
Wayne Roberts 0:d88677306896 246 }
Wayne Roberts 0:d88677306896 247
Wayne Roberts 0:d88677306896 248 Radio::radio.tx_buf[1] = f.octet;
Wayne Roberts 0:d88677306896 249
Wayne Roberts 0:d88677306896 250 c = crc16(Radio::radio.tx_buf, txCurs);
Wayne Roberts 0:d88677306896 251 Radio::radio.tx_buf[txCurs++] = c >> 8;
Wayne Roberts 0:d88677306896 252 Radio::radio.tx_buf[txCurs++] = c;
Wayne Roberts 0:d88677306896 253
Wayne Roberts 0:d88677306896 254 Radio::Send(txCurs, 0, 0, 0);
Wayne Roberts 0:d88677306896 255 state = STATE_ACK_WAITING;
Wayne Roberts 0:d88677306896 256 flags._sleep_ = 0;
Wayne Roberts 0:d88677306896 257
Wayne Roberts 0:d88677306896 258 return txCurs;
Wayne Roberts 0:d88677306896 259 } // .._tx_forward()
Wayne Roberts 0:d88677306896 260
Wayne Roberts 0:d88677306896 261 volatile us_timestamp_t prevFwdStart;
Wayne Roberts 0:d88677306896 262
Wayne Roberts 0:d88677306896 263 void tx_forward_cb()
Wayne Roberts 0:d88677306896 264 {
Wayne Roberts 0:d88677306896 265 unsigned dur;
Wayne Roberts 0:d88677306896 266 uint8_t txlen;
Wayne Roberts 0:d88677306896 267 us_timestamp_t now;
Wayne Roberts 0:d88677306896 268
Wayne Roberts 0:d88677306896 269 now = Radio::lpt.read_us();
Wayne Roberts 0:d88677306896 270
Wayne Roberts 0:d88677306896 271 if (measuredIntervalSaved != 0) // in case nothing received
Wayne Roberts 0:d88677306896 272 mbedTImeout_forwarder.attach_us(tx_forward_cb, measuredIntervalSaved);
Wayne Roberts 0:d88677306896 273
Wayne Roberts 0:d88677306896 274 Radio::radio.tx_buf[1] = 0; //initialize flags
Wayne Roberts 0:d88677306896 275 forwardLenAckd = 0;
Wayne Roberts 0:d88677306896 276
Wayne Roberts 0:d88677306896 277 txlen = _tx_forward();
Wayne Roberts 0:d88677306896 278
Wayne Roberts 0:d88677306896 279 flags.mbedTImeout_forwarderStarted = 0;
Wayne Roberts 0:d88677306896 280
Wayne Roberts 0:d88677306896 281 dur = Radio::lora_toa_us(txlen);
Wayne Roberts 0:d88677306896 282 pc.printf("\e[7mtx_forward_cb %d", now - prevFwdStart - TX_INTERVAL_US);
Wayne Roberts 0:d88677306896 283 pc.printf(" dur%u\e[0m\r\n", dur);
Wayne Roberts 0:d88677306896 284 prevFwdStart = now;
Wayne Roberts 0:d88677306896 285 }
Wayne Roberts 0:d88677306896 286 #else // ..UNIT_LAST:
Wayne Roberts 0:d88677306896 287 void uart_forward_cb()
Wayne Roberts 0:d88677306896 288 {
Wayne Roberts 0:d88677306896 289 if (measuredIntervalSaved != 0) // in case nothing received
Wayne Roberts 0:d88677306896 290 mbedTImeout_forwarder.attach_us(uart_forward_cb, measuredIntervalSaved);
Wayne Roberts 0:d88677306896 291
Wayne Roberts 0:d88677306896 292 forwardLenAckd = 0;
Wayne Roberts 0:d88677306896 293 print_payload();
Wayne Roberts 0:d88677306896 294
Wayne Roberts 0:d88677306896 295 setupNext();
Wayne Roberts 0:d88677306896 296
Wayne Roberts 0:d88677306896 297 flags.mbedTImeout_forwarderStarted = 0;
Wayne Roberts 0:d88677306896 298 }
Wayne Roberts 0:d88677306896 299 #endif /* UNIT_LAST */
Wayne Roberts 0:d88677306896 300
Wayne Roberts 0:d88677306896 301 void nextRxStartCB()
Wayne Roberts 0:d88677306896 302 {
Wayne Roberts 0:d88677306896 303 unsigned us;
Wayne Roberts 0:d88677306896 304
Wayne Roberts 0:d88677306896 305 Radio::Rx();
Wayne Roberts 0:d88677306896 306 rxStartAt = Radio::lpt.read_us();
Wayne Roberts 0:d88677306896 307 flags._sleep_ = 0;
Wayne Roberts 0:d88677306896 308
Wayne Roberts 0:d88677306896 309 us = (MAX_TX_ATTEMPTS * retryInterval_us) + (MAX_TX_ATTEMPTS * TXRX_PADDING_US);
Wayne Roberts 0:d88677306896 310
Wayne Roberts 0:d88677306896 311 pc.printf("nextRxStartCB for %uus\r\n", us);
Wayne Roberts 0:d88677306896 312 }
Wayne Roberts 0:d88677306896 313
Wayne Roberts 0:d88677306896 314
Wayne Roberts 0:d88677306896 315 void txDoneCB()
Wayne Roberts 0:d88677306896 316 {
Wayne Roberts 0:d88677306896 317 char str[32];
Wayne Roberts 0:d88677306896 318
Wayne Roberts 0:d88677306896 319 Radio::Rx();
Wayne Roberts 0:d88677306896 320 stateToString(state, str);
Wayne Roberts 0:d88677306896 321 pc.printf("%s:txDone->Rx\r\n", str);
Wayne Roberts 0:d88677306896 322 }
Wayne Roberts 0:d88677306896 323
Wayne Roberts 0:d88677306896 324 void rxDoneCB(uint8_t size, float rssi, float snr)
Wayne Roberts 0:d88677306896 325 {
Wayne Roberts 0:d88677306896 326 pkt_flags_t f;
Wayne Roberts 0:d88677306896 327 char str[32];
Wayne Roberts 0:d88677306896 328 us_timestamp_t rxIrqAt = Radio::irqAt;
Wayne Roberts 0:d88677306896 329
Wayne Roberts 0:d88677306896 330 stateToString(state, str);
Wayne Roberts 0:d88677306896 331 pc.printf("\e[33mrxDoneCB() %u rssi:%.1fdBm snr:%.1fdB %s ID:%02x\e[0m ", size, rssi, snr, str, Radio::radio.rx_buf[0]);
Wayne Roberts 0:d88677306896 332 if (state == STATE_GET_REQ) {
Wayne Roberts 0:d88677306896 333 uint8_t len;
Wayne Roberts 0:d88677306896 334 unsigned c, rxc;
Wayne Roberts 0:d88677306896 335 if (Radio::radio.rx_buf[0] != UNIT_ID-1) {
Wayne Roberts 0:d88677306896 336 pc.printf("\r\n");
Wayne Roberts 0:d88677306896 337 return;
Wayne Roberts 0:d88677306896 338 }
Wayne Roberts 0:d88677306896 339 if (size < 4) {
Wayne Roberts 0:d88677306896 340 /* minimum: header + crc */
Wayne Roberts 0:d88677306896 341 pc.printf("\r\n");
Wayne Roberts 0:d88677306896 342 return;
Wayne Roberts 0:d88677306896 343 }
Wayne Roberts 0:d88677306896 344 f.octet = Radio::radio.rx_buf[1];
Wayne Roberts 0:d88677306896 345
Wayne Roberts 0:d88677306896 346 c = crc16(Radio::radio.rx_buf, size-2);
Wayne Roberts 0:d88677306896 347 rxc = Radio::radio.rx_buf[size-2];
Wayne Roberts 0:d88677306896 348 rxc <<= 8;
Wayne Roberts 0:d88677306896 349 rxc |= Radio::radio.rx_buf[size-1];
Wayne Roberts 0:d88677306896 350 if (c != rxc) {
Wayne Roberts 0:d88677306896 351 pc.printf("\e[31mfrom%02x c:%04x rxc:%04x\e[0m\r\n", Radio::radio.rx_buf[0], c, rxc);
Wayne Roberts 0:d88677306896 352 for (unsigned n = 0; n < size; n++)
Wayne Roberts 0:d88677306896 353 pc.printf("%02x ", Radio::radio.rx_buf[n]);
Wayne Roberts 0:d88677306896 354 pc.printf("\r\n");
Wayne Roberts 0:d88677306896 355 return;
Wayne Roberts 0:d88677306896 356 }
Wayne Roberts 0:d88677306896 357 //noRxTimeout.detach();
Wayne Roberts 0:d88677306896 358
Wayne Roberts 0:d88677306896 359 pc.printf(" attempt%u frag%u fragLast%u ", f.bits.attempt, f.bits.fragNum, f.bits.fragLast);
Wayne Roberts 0:d88677306896 360 if (state == STATE_GET_REQ && flags.mbedTImeout_forwarderStarted == 0 && f.bits.fragLast) {
Wayne Roberts 0:d88677306896 361 us_timestamp_t now;
Wayne Roberts 0:d88677306896 362 unsigned sinceRxDone, us;
Wayne Roberts 0:d88677306896 363 mbedTImeout_forwarder.detach();
Wayne Roberts 0:d88677306896 364 now = Radio::lpt.read_us();
Wayne Roberts 0:d88677306896 365 sinceRxDone = now - rxIrqAt;
Wayne Roberts 0:d88677306896 366 us = retryInterval_us * (MAX_TX_ATTEMPTS - f.bits.attempt);
Wayne Roberts 0:d88677306896 367 int target_us = us - sinceRxDone;
Wayne Roberts 0:d88677306896 368 // tx to occur after time given for all potential retries
Wayne Roberts 0:d88677306896 369 #ifndef UNIT_LAST
Wayne Roberts 0:d88677306896 370 mbedTImeout_forwarder.attach_us(tx_forward_cb, target_us);
Wayne Roberts 0:d88677306896 371 #else
Wayne Roberts 0:d88677306896 372 mbedTImeout_forwarder.attach_us(uart_forward_cb, target_us);
Wayne Roberts 0:d88677306896 373 #endif /* UNIT_LAST */
Wayne Roberts 0:d88677306896 374 pc.printf("schedule forward %u, forwarding in %dus. sinceRxDone:%u\r\n", MAX_TX_ATTEMPTS - f.bits.attempt, target_us, sinceRxDone);
Wayne Roberts 0:d88677306896 375 flags.mbedTImeout_forwarderStarted = 1;
Wayne Roberts 0:d88677306896 376 forwardedAt = now + target_us;
Wayne Roberts 0:d88677306896 377 }
Wayne Roberts 0:d88677306896 378
Wayne Roberts 0:d88677306896 379 Radio::radio.tx_buf[0] = UNIT_ID; // OK, send ACK
Wayne Roberts 0:d88677306896 380 Radio::Send(1, 0, 0, 0);
Wayne Roberts 0:d88677306896 381
Wayne Roberts 0:d88677306896 382
Wayne Roberts 0:d88677306896 383 if (prevFrag != f.bits.fragNum) {
Wayne Roberts 0:d88677306896 384 len = size - 4; // -4: header ... crc
Wayne Roberts 0:d88677306896 385 memcpy(forward + forwardLen, Radio::radio.rx_buf+2, len);
Wayne Roberts 0:d88677306896 386 forwardLen += len;
Wayne Roberts 0:d88677306896 387
Wayne Roberts 0:d88677306896 388 prevFrag = f.bits.fragNum;
Wayne Roberts 0:d88677306896 389 }
Wayne Roberts 0:d88677306896 390
Wayne Roberts 0:d88677306896 391 if (f.bits.fragNum == 0) {
Wayne Roberts 0:d88677306896 392 unsigned attemptOffset = retryInterval_us * f.bits.attempt;
Wayne Roberts 0:d88677306896 393 if (rxStartAt == 0) {
Wayne Roberts 0:d88677306896 394 pc.printf("\e[7m");
Wayne Roberts 0:d88677306896 395 }
Wayne Roberts 0:d88677306896 396 pc.printf("lastRxIrqAt:%u measuredInterval:%llu ", lastRxIrqAt, measuredInterval);
Wayne Roberts 0:d88677306896 397 if (lastRxIrqAt != 0) {
Wayne Roberts 0:d88677306896 398 us_timestamp_t thisMeas;
Wayne Roberts 0:d88677306896 399 int err_;
Wayne Roberts 0:d88677306896 400 unsigned abserr;
Wayne Roberts 0:d88677306896 401 thisMeas = (rxIrqAt - attemptOffset) - lastRxIrqAt;
Wayne Roberts 0:d88677306896 402 err_ = thisMeas - TX_INTERVAL_US;
Wayne Roberts 0:d88677306896 403 if (TX_INTERVAL_US > thisMeas)
Wayne Roberts 0:d88677306896 404 abserr = TX_INTERVAL_US - thisMeas;
Wayne Roberts 0:d88677306896 405 else
Wayne Roberts 0:d88677306896 406 abserr = thisMeas - TX_INTERVAL_US;
Wayne Roberts 0:d88677306896 407
Wayne Roberts 0:d88677306896 408 pc.printf(" this:%llu err_:%d ", thisMeas, err_);
Wayne Roberts 0:d88677306896 409 if (abserr < MEASURED_MAX_ERR) {
Wayne Roberts 0:d88677306896 410 int rxPrecedency = 0;
Wayne Roberts 0:d88677306896 411 unsigned sinceRxDone, _us_;
Wayne Roberts 0:d88677306896 412 unsigned pktDur = Radio::lora_toa_us(size);
Wayne Roberts 0:d88677306896 413 us_timestamp_t firstAttemptStartedAt = (rxIrqAt - attemptOffset) - pktDur;
Wayne Roberts 0:d88677306896 414
Wayne Roberts 0:d88677306896 415 measuredInterval = thisMeas;
Wayne Roberts 0:d88677306896 416 _us_ = measuredInterval;
Wayne Roberts 0:d88677306896 417 pc.printf("->%llu ", measuredInterval);
Wayne Roberts 0:d88677306896 418
Wayne Roberts 0:d88677306896 419 if (rxStartAt != 0) {
Wayne Roberts 0:d88677306896 420 rxPrecedency = firstAttemptStartedAt - rxStartAt;
Wayne Roberts 0:d88677306896 421 if (rxPrecedency > 0)
Wayne Roberts 0:d88677306896 422 _us_ += rxPrecedency / 2;
Wayne Roberts 0:d88677306896 423 else
Wayne Roberts 0:d88677306896 424 _us_ += rxPrecedency;
Wayne Roberts 0:d88677306896 425 }
Wayne Roberts 0:d88677306896 426
Wayne Roberts 0:d88677306896 427 _us_ -= rxStartup_us;
Wayne Roberts 0:d88677306896 428 _us_ -= retryInterval_us; // TODO
Wayne Roberts 0:d88677306896 429 mbedTimeout_nextRx.detach();
Wayne Roberts 0:d88677306896 430 sinceRxDone = Radio::lpt.read_us() - rxIrqAt;
Wayne Roberts 0:d88677306896 431 mbedTimeout_nextRx.attach_us(nextRxStartCB, _us_ - sinceRxDone);
Wayne Roberts 0:d88677306896 432 pc.printf("nextRx:%u ao%u rxPrecedency:%d pktDur%u ri%u sinceRxDone%u ", _us_ - sinceRxDone, attemptOffset, rxPrecedency, pktDur, retryInterval_us, sinceRxDone);
Wayne Roberts 0:d88677306896 433
Wayne Roberts 0:d88677306896 434 if (measuredIntervalSaved == 0)
Wayne Roberts 0:d88677306896 435 measuredIntervalSaved = measuredInterval;
Wayne Roberts 0:d88677306896 436 else {
Wayne Roberts 0:d88677306896 437 measuredIntervalSaved += measuredInterval;
Wayne Roberts 0:d88677306896 438 measuredIntervalSaved /= 2;
Wayne Roberts 0:d88677306896 439 }
Wayne Roberts 0:d88677306896 440
Wayne Roberts 0:d88677306896 441 rxStartAt = 0;
Wayne Roberts 0:d88677306896 442 } else
Wayne Roberts 0:d88677306896 443 pc.printf("\e[31mtoo-much-err\e[0m\r\n");
Wayne Roberts 0:d88677306896 444
Wayne Roberts 0:d88677306896 445 pc.printf("\r\n");
Wayne Roberts 0:d88677306896 446 } // ..if (lastRxIrqAt != 0)
Wayne Roberts 0:d88677306896 447
Wayne Roberts 0:d88677306896 448 lastRxIrqAt = rxIrqAt - attemptOffset;
Wayne Roberts 0:d88677306896 449
Wayne Roberts 0:d88677306896 450 pc.printf("\e[0m");
Wayne Roberts 0:d88677306896 451 } // ..if (f.bits.fragNum == 0)
Wayne Roberts 0:d88677306896 452
Wayne Roberts 0:d88677306896 453 } // ..if (state == STATE_GET_REQ)
Wayne Roberts 0:d88677306896 454 #ifndef UNIT_LAST
Wayne Roberts 0:d88677306896 455 else if (state == STATE_ACK_WAITING) {
Wayne Roberts 0:d88677306896 456
Wayne Roberts 0:d88677306896 457 if (Radio::radio.rx_buf[0] == UNIT_ID+1) {
Wayne Roberts 0:d88677306896 458 pkt_flags_t f;
Wayne Roberts 0:d88677306896 459 f.octet = Radio::radio.tx_buf[1];
Wayne Roberts 0:d88677306896 460
Wayne Roberts 0:d88677306896 461 tickerRetry.detach();
Wayne Roberts 0:d88677306896 462 forwardLenAckd = forwardLenTransmitted;
Wayne Roberts 0:d88677306896 463 if (f.bits.fragLast) {
Wayne Roberts 0:d88677306896 464 pc.printf("ackOk-last ");
Wayne Roberts 0:d88677306896 465 #if (UNIT_ID == 0x00)
Wayne Roberts 0:d88677306896 466 pc.printf("->SLEEP ");
Wayne Roberts 0:d88677306896 467 flags._sleep_ = 1;
Wayne Roberts 0:d88677306896 468 Radio::Sleep();
Wayne Roberts 0:d88677306896 469 #else
Wayne Roberts 0:d88677306896 470 setupNext();
Wayne Roberts 0:d88677306896 471 #endif /* UNIT_ID != 0x00 */
Wayne Roberts 0:d88677306896 472 } else {
Wayne Roberts 0:d88677306896 473 f.bits.fragNum++;
Wayne Roberts 0:d88677306896 474 f.bits.attempt = 0;
Wayne Roberts 0:d88677306896 475 Radio::radio.tx_buf[1] = f.octet;
Wayne Roberts 0:d88677306896 476 _tx_forward();
Wayne Roberts 0:d88677306896 477 pc.printf("ackOk->%u ", f.bits.fragNum);
Wayne Roberts 0:d88677306896 478 }
Wayne Roberts 0:d88677306896 479 } else
Wayne Roberts 0:d88677306896 480 pc.printf("ack from different ID %02x\r\n", Radio::radio.rx_buf[0]);
Wayne Roberts 0:d88677306896 481 }
Wayne Roberts 0:d88677306896 482 #endif /* UNIT_LAST */
Wayne Roberts 0:d88677306896 483
Wayne Roberts 0:d88677306896 484 pc.printf("\r\n");
Wayne Roberts 0:d88677306896 485 } // ..rxDoneCB()
Wayne Roberts 0:d88677306896 486
Wayne Roberts 0:d88677306896 487 #if (UNIT_ID == 0x00) && !defined(UNIT_LAST)
Wayne Roberts 0:d88677306896 488 LowPowerTicker lpTicker;
Wayne Roberts 0:d88677306896 489
Wayne Roberts 0:d88677306896 490 void tx_ticker_cb(void) {
Wayne Roberts 0:d88677306896 491 unsigned c;
Wayne Roberts 0:d88677306896 492 pkt_flags_t f;
Wayne Roberts 0:d88677306896 493 message_t* mptr;
Wayne Roberts 0:d88677306896 494
Wayne Roberts 0:d88677306896 495 tickerRetry.attach_us(retry_cb, retryInterval_us);
Wayne Roberts 0:d88677306896 496
Wayne Roberts 0:d88677306896 497 f.bits.attempt = 0;
Wayne Roberts 0:d88677306896 498 f.bits.fragNum = 0;
Wayne Roberts 0:d88677306896 499 f.bits.fragLast = 1;
Wayne Roberts 0:d88677306896 500
Wayne Roberts 0:d88677306896 501 txCurs = 0;
Wayne Roberts 0:d88677306896 502 Radio::radio.tx_buf[txCurs++] = UNIT_ID;
Wayne Roberts 0:d88677306896 503 Radio::radio.tx_buf[txCurs++] = f.octet;
Wayne Roberts 0:d88677306896 504
Wayne Roberts 0:d88677306896 505 mptr = (message_t*)(Radio::radio.tx_buf + txCurs);
Wayne Roberts 0:d88677306896 506 mptr->unit_id = UNIT_ID;
Wayne Roberts 0:d88677306896 507 mptr->flags = 0x00;
Wayne Roberts 0:d88677306896 508 mptr->sample = ain.read_u16();
Wayne Roberts 0:d88677306896 509 #ifdef N_SMP
Wayne Roberts 0:d88677306896 510 for (c = 0; c < N_SMP; c++)
Wayne Roberts 0:d88677306896 511 mptr->samples[c] = ain.read_u16();
Wayne Roberts 0:d88677306896 512 #endif
Wayne Roberts 0:d88677306896 513 txCurs += sizeof(message_t);
Wayne Roberts 0:d88677306896 514
Wayne Roberts 0:d88677306896 515 c = crc16(Radio::radio.tx_buf, txCurs);
Wayne Roberts 0:d88677306896 516 Radio::radio.tx_buf[txCurs++] = c >> 8;
Wayne Roberts 0:d88677306896 517 Radio::radio.tx_buf[txCurs++] = c;
Wayne Roberts 0:d88677306896 518
Wayne Roberts 0:d88677306896 519 Radio::Send(txCurs, 0, 0, 0);
Wayne Roberts 0:d88677306896 520 state = STATE_ACK_WAITING;
Wayne Roberts 0:d88677306896 521 pc.printf("tx_ticker_cb:%u \r\n", mptr->sample);
Wayne Roberts 0:d88677306896 522 flags._sleep_ = 0;
Wayne Roberts 0:d88677306896 523 }
Wayne Roberts 0:d88677306896 524 #endif /* UNIT_ID == 0x00 */
Wayne Roberts 0:d88677306896 525
Wayne Roberts 0:d88677306896 526 void uart_rx()
Wayne Roberts 0:d88677306896 527 {
Wayne Roberts 0:d88677306896 528 char str[32];
Wayne Roberts 0:d88677306896 529
Wayne Roberts 0:d88677306896 530 char ch = pc.getc();
Wayne Roberts 0:d88677306896 531 switch (ch) {
Wayne Roberts 0:d88677306896 532 case '+':
Wayne Roberts 0:d88677306896 533 rxStartup_us += 500;
Wayne Roberts 0:d88677306896 534 pc.printf("rxStartup_us:%u\r\n", rxStartup_us);
Wayne Roberts 0:d88677306896 535 break;
Wayne Roberts 0:d88677306896 536 case '-':
Wayne Roberts 0:d88677306896 537 if (rxStartup_us > 500)
Wayne Roberts 0:d88677306896 538 rxStartup_us -= 500;
Wayne Roberts 0:d88677306896 539 pc.printf("rxStartup_us:%u\r\n", rxStartup_us);
Wayne Roberts 0:d88677306896 540 break;
Wayne Roberts 0:d88677306896 541 case '.':
Wayne Roberts 0:d88677306896 542 Radio::PrintStatus();
Wayne Roberts 0:d88677306896 543 printf("UNIT_ID:%02x ", UNIT_ID);
Wayne Roberts 0:d88677306896 544 printf(" measuredInterval:%llu\r\n", measuredInterval);
Wayne Roberts 0:d88677306896 545 stateToString(state, str);
Wayne Roberts 0:d88677306896 546 printf("_sleep_:%u %s\r\n", flags._sleep_, str);
Wayne Roberts 0:d88677306896 547 break;
Wayne Roberts 0:d88677306896 548 case 'r':
Wayne Roberts 0:d88677306896 549 flags.run ^= 1;
Wayne Roberts 0:d88677306896 550 printf("\r\nrun %u\r\n", flags.run);
Wayne Roberts 0:d88677306896 551 if (flags.run == 0) {
Wayne Roberts 0:d88677306896 552 #ifndef UNIT_LAST
Wayne Roberts 0:d88677306896 553 tickerRetry.detach();
Wayne Roberts 0:d88677306896 554 #endif /* !UNIT_LAST */
Wayne Roberts 0:d88677306896 555 mbedTImeout_forwarder.detach();
Wayne Roberts 0:d88677306896 556 mbedTimeout_nextRx.detach();
Wayne Roberts 0:d88677306896 557
Wayne Roberts 0:d88677306896 558 flags._sleep_ = 1;
Wayne Roberts 0:d88677306896 559 Radio::Sleep();
Wayne Roberts 0:d88677306896 560 }
Wayne Roberts 0:d88677306896 561 break;
Wayne Roberts 0:d88677306896 562 } // ..switch (ch)
Wayne Roberts 0:d88677306896 563 }
Wayne Roberts 0:d88677306896 564
Wayne Roberts 0:d88677306896 565 int main()
Wayne Roberts 0:d88677306896 566 {
Wayne Roberts 0:d88677306896 567 flags.run = 1;
Wayne Roberts 0:d88677306896 568 pc.baud(115200);
Wayne Roberts 0:d88677306896 569 pc.printf("\r\nreset\r\n");
Wayne Roberts 0:d88677306896 570 Radio::Init(txDoneCB, rxDoneCB);
Wayne Roberts 0:d88677306896 571
Wayne Roberts 0:d88677306896 572 Radio::setFrfMHz(CF_MHZ);
Wayne Roberts 0:d88677306896 573 Radio::Config(500, SPREADING_FACTOR);
Wayne Roberts 0:d88677306896 574
Wayne Roberts 0:d88677306896 575 /* max TX length + turnaround + ACK length */
Wayne Roberts 0:d88677306896 576 retryInterval_us = Radio::lora_toa_us(MAX_TX_LENGTH) + TXRX_PADDING_US + Radio::lora_toa_us(1);
Wayne Roberts 0:d88677306896 577 #ifdef UNIT_LAST
Wayne Roberts 0:d88677306896 578 pc.printf("LAST ");
Wayne Roberts 0:d88677306896 579 #endif
Wayne Roberts 0:d88677306896 580 pc.printf("UNIT_ID:%02x retryInterval_us:%u\r\n", UNIT_ID, retryInterval_us);
Wayne Roberts 0:d88677306896 581
Wayne Roberts 0:d88677306896 582 flags._sleep_ = 0;
Wayne Roberts 0:d88677306896 583 state = STATE_NONE;
Wayne Roberts 0:d88677306896 584
Wayne Roberts 0:d88677306896 585 #if (UNIT_ID == 0x00) && !defined(UNIT_LAST)
Wayne Roberts 0:d88677306896 586 lpTicker.attach_us(tx_ticker_cb, TX_INTERVAL_US);
Wayne Roberts 0:d88677306896 587 #else
Wayne Roberts 0:d88677306896 588 Radio::PrintStatus();
Wayne Roberts 0:d88677306896 589
Wayne Roberts 0:d88677306896 590 setupNext();
Wayne Roberts 0:d88677306896 591
Wayne Roberts 0:d88677306896 592 measuredInterval = 0;
Wayne Roberts 0:d88677306896 593 lastRxIrqAt = 0;
Wayne Roberts 0:d88677306896 594 measuredIntervalSaved = 0;
Wayne Roberts 0:d88677306896 595 #endif /* UNIT_ID != 0x00 */
Wayne Roberts 0:d88677306896 596
Wayne Roberts 0:d88677306896 597 if (sleep_manager_can_deep_sleep())
Wayne Roberts 0:d88677306896 598 sleep_manager_lock_deep_sleep(); // prevent deep sleep
Wayne Roberts 0:d88677306896 599
Wayne Roberts 0:d88677306896 600 for (;;) {
Wayne Roberts 0:d88677306896 601 if (pc.readable()) {
Wayne Roberts 0:d88677306896 602 uart_rx();
Wayne Roberts 0:d88677306896 603 }
Wayne Roberts 0:d88677306896 604
Wayne Roberts 0:d88677306896 605 if (flags._sleep_ == 0) {
Wayne Roberts 0:d88677306896 606 Radio::service();
Wayne Roberts 0:d88677306896 607 } else
Wayne Roberts 0:d88677306896 608 sleep_manager_sleep_auto();;
Wayne Roberts 0:d88677306896 609
Wayne Roberts 0:d88677306896 610 } // ..for (;;)
Wayne Roberts 0:d88677306896 611 }
Wayne Roberts 0:d88677306896 612