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

Dependencies:   sx12xx_hal

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "radio.h" 
00002 
00003 #define UNIT_ID     0x00            /* 0x00: first unit */
00004 //#define UNIT_LAST
00005 
00006 // test large sample, large pkt size  #define N_SMP    10
00007 typedef struct __attribute__((__packed__)) msg {
00008     uint8_t unit_id;
00009     uint8_t flags;
00010     uint16_t sample;
00011 
00012     #ifdef N_SMP
00013     uint16_t samples[N_SMP];
00014     #endif
00015 } message_t;
00016 
00017 #define TX_INTERVAL_US              5000000
00018 #define MAX_TX_LENGTH               64
00019 #define TXRX_PADDING_US             10000
00020 #define MAX_TX_ATTEMPTS             4
00021 #define SPREADING_FACTOR            9
00022 #ifdef SX128x_H
00023     #define CF_MHZ                      2487.0
00024     #define BW_KHZ                      200
00025     #define TX_DBM                      12
00026 #else
00027     #define CF_MHZ                      917.6
00028     #define BW_KHZ                      500
00029     #define TX_DBM                      17
00030 #endif
00031 
00032 #define EXPECTED_LENGTH     (UNIT_ID * sizeof(message_t))
00033 //#define MEASURED_MAX_ERR        (TX_INTERVAL_US / 4000)     // +/-100ppm allowance
00034 #define MEASURED_MAX_ERR        (TX_INTERVAL_US / 300)     // +/-Xppm allowance
00035 
00036 #if defined(SX127x_H)
00037     #define RX_STARTUP_US           1500
00038 #elif defined(SX126x_H)
00039     #define RX_STARTUP_US           1000
00040 #elif defined(SX128x_H)
00041     #define RX_STARTUP_US           1000
00042 #endif
00043 unsigned rxStartup_us = RX_STARTUP_US;
00044 
00045 RawSerial pc(USBTX, USBRX); 
00046 DigitalIn button(USER_BUTTON);
00047 
00048 #ifdef TARGET_DISCO_L072CZ_LRWAN1
00049         AnalogIn ain(A0);
00050 #elif defined(TARGET_MOTE_L152RC)
00051         AnalogIn ain(A0);
00052 #else
00053     #ifdef TARGET_FF_MORPHO
00054         AnalogIn ain(PC_4); // pin unused by arduino shields
00055     #endif /* TARGET_FF_MORPHO */
00056 #endif /* !TARGET_DISCO_L072CZ_LRWAN1 */
00057 
00058 uint8_t forward_buf[255];
00059 uint8_t forwardLen;
00060 uint8_t forwardLenTransmitted;
00061 uint8_t forwardLenAckd;
00062 int prevFrag;
00063 volatile us_timestamp_t forwardedAt;
00064 
00065 volatile us_timestamp_t lastRxIrqAt;
00066 volatile us_timestamp_t measuredInterval, measuredIntervalSaved;
00067 
00068 
00069 enum _state_ {
00070     /* 0 */ STATE_NONE = 0,
00071 #if (UNIT_ID != 0x00)
00072     /* 1 */ STATE_GET_REQ,
00073 #endif /* UNIT_ID != 0x00 */
00074 #ifndef UNIT_LAST
00075     /* 2 */ STATE_ACK_WAITING,
00076     /* 3 */ STATE_TX_FORWARD,
00077 #endif /* UNIT_LAST */
00078 } state;
00079 
00080 void stateToString(enum _state_ s, char* out)
00081 {
00082     const char* str;
00083 
00084     switch (s) {
00085         case STATE_NONE: str = "NONE"; break;
00086 #if (UNIT_ID != 0x00)
00087         case STATE_GET_REQ: str = "GET_REQ"; break;
00088 #endif /* UNIT_ID != 0x00 */
00089 #ifndef UNIT_LAST
00090         case STATE_ACK_WAITING: str = "ACK_WAITING"; break;
00091         case STATE_TX_FORWARD: str = "TX_FORWARD"; break;
00092 #endif /* UNIT_LAST */
00093         default:
00094             sprintf(out, "??%u??", s);
00095             return;
00096     }
00097 
00098     strcpy(out, str);
00099 }
00100 
00101 typedef union {
00102     struct {
00103         uint8_t attempt : 3;    // 0,1,2
00104         uint8_t fragNum : 4;    // 3,4,5,6
00105         uint8_t fragLast : 1;   // 7
00106     } bits;
00107     uint8_t octet;
00108 } pkt_flags_t;
00109 
00110 volatile struct _f_ {
00111     uint8_t unused                      : 1;   // 0
00112     uint8_t mbedTImeout_forwarderStarted: 1;   // 1
00113     uint8_t run                         : 1;   // 2
00114     uint8_t svc                         : 1;   // 3
00115 #ifndef UNIT_LAST
00116     uint8_t sample                      : 1;   // 4
00117     uint8_t fwd                         : 1;   // 5
00118 #endif /* UNIT_LAST */
00119 } flags;
00120 
00121 
00122 static uint16_t crc16( uint8_t *buffer, uint16_t length )
00123 {
00124     uint16_t i;
00125     // The CRC calculation follows CCITT
00126     const uint16_t polynom = 0x1021;
00127     // CRC initial value
00128     uint16_t crc = 0x0000;
00129 
00130     if( buffer == NULL )
00131     {
00132         return 0;
00133     }
00134 
00135     for( i = 0; i < length; ++i )
00136     {
00137         uint16_t j;
00138         crc ^= ( uint16_t ) buffer[i] << 8;
00139         for( j = 0; j < 8; ++j )
00140         {
00141             crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
00142         }
00143     }
00144 
00145     return crc;
00146 }
00147 
00148 #ifdef UNIT_LAST
00149 void print_payload()
00150 {
00151     unsigned n;
00152 
00153     for (n = 0; n < forwardLen; n += sizeof(message_t)) {
00154         const message_t* m = (message_t*)&forward_buf[n];
00155 
00156         pc.printf("unit %02x: %02x, %u\r\n", m->unit_id, m->flags, m->sample);
00157     }
00158 
00159 }
00160 #endif /* UNIT_LAST */
00161 
00162 LowPowerTimeout mbedTimeout_nextRx;
00163 volatile unsigned retryInterval_us;
00164 volatile us_timestamp_t rxStartAt;
00165 
00166 #if (UNIT_ID != 0x00)
00167 void setupNext()
00168 {
00169     state = STATE_GET_REQ;
00170     forwardLen = 0;
00171     prevFrag = -1;
00172     pc.printf("->GET_REQ ");
00173 
00174     if (measuredInterval > 0) {
00175         Radio::Sleep();
00176         pc.printf("SLEEP mi:%llu ", measuredInterval);
00177         measuredInterval = 0; // single use
00178     } else {
00179         Radio::Rx(0);
00180 
00181         rxStartAt = 0;  // starting of continuous rx not used
00182 
00183 #ifndef UNIT_LAST
00184         flags.sample = 1;
00185 #endif /* UNIT_LAST */
00186         pc.printf("RX ");
00187     }
00188 
00189     memset(forward_buf, 0xff, EXPECTED_LENGTH);
00190 }
00191 #endif /* UNIT_ID != 0x00 */
00192 
00193 LowPowerTimeout mbedTImeout_forwarder;
00194 
00195 
00196 #ifndef UNIT_LAST
00197 volatile uint8_t txCurs;
00198 
00199 LowPowerTicker tickerRetry;
00200 volatile us_timestamp_t txStartAt;
00201 
00202 void retry_cb()
00203 {
00204     unsigned c;
00205     pkt_flags_t f;
00206 
00207     Radio::Standby();
00208 
00209     f.octet = Radio::radio.tx_buf[1];
00210     pc.printf("attempt%u", f.bits.attempt);
00211     if (++f.bits.attempt >= MAX_TX_ATTEMPTS) {
00212         pc.printf(" lastTry");
00213         tickerRetry.detach();
00214 #if (UNIT_ID != 0x00)
00215         setupNext();
00216 #endif /* UNIT_ID != 0x00 */
00217         pc.printf("\r\n");
00218         return;
00219     }
00220     pc.printf("->%u\r\n", f.bits.attempt);
00221     Radio::radio.tx_buf[1] = f.octet;
00222 
00223     c = crc16(Radio::radio.tx_buf, txCurs-2);
00224     Radio::radio.tx_buf[txCurs-2] = c >> 8;
00225     Radio::radio.tx_buf[txCurs-1] = c;
00226 
00227     txStartAt = Radio::lpt.read_us();
00228     Radio::Send(txCurs, 0, 0, 0);
00229     state = STATE_ACK_WAITING;
00230 }
00231 
00232 volatile uint16_t sample;
00233 
00234 #ifdef N_SMP
00235 volatile uint16_t samples[N_SMP];
00236 #endif
00237 
00238 #if (UNIT_ID != 0x00)
00239 uint8_t _tx_forward()
00240 {
00241     unsigned fwdLen;
00242     unsigned c;
00243     uint8_t added, avail, toSendLen, stop = MAX_TX_LENGTH-2;
00244     pkt_flags_t f;
00245 
00246     tickerRetry.attach_us(retry_cb, retryInterval_us);
00247 
00248     if (forwardLen < EXPECTED_LENGTH) {
00249         pc.printf("\e[31mmissing %u bytes\e[0m ", EXPECTED_LENGTH - forwardLen);
00250         fwdLen = EXPECTED_LENGTH;
00251     }
00252         fwdLen = forwardLen;
00253 
00254     f.octet = Radio::radio.tx_buf[1];
00255 
00256     txCurs = 0;
00257     Radio::radio.tx_buf[txCurs++] = UNIT_ID;
00258     txCurs++;   // placeholder for flags to be added at end
00259 
00260     toSendLen = fwdLen - forwardLenAckd;
00261     forwardLenTransmitted = forwardLenAckd;
00262     added = 0;
00263     while ((txCurs + sizeof(message_t)) < stop && added < toSendLen) {
00264         memcpy(Radio::radio.tx_buf + txCurs, forward_buf + forwardLenTransmitted, sizeof(message_t));
00265         forwardLenTransmitted += sizeof(message_t);
00266         txCurs += sizeof(message_t);
00267         added += sizeof(message_t);
00268     }
00269 
00270     avail = stop - txCurs;
00271     if (avail >= sizeof(message_t)) {
00272         message_t* mptr = (message_t*)(Radio::radio.tx_buf + txCurs);
00273         mptr->unit_id = UNIT_ID;
00274         mptr->flags = 0x00;
00275         mptr->sample = sample;  // taken from main loop
00276 #ifdef N_SMP
00277         for (c = 0; c < N_SMP; c++)
00278             mptr->samples[c] = samples[c];  // taken from main loop
00279 #endif
00280         txCurs += sizeof(message_t);
00281 
00282         f.bits.fragLast = 1;
00283     }
00284 
00285     Radio::radio.tx_buf[1] = f.octet;
00286 
00287     c = crc16(Radio::radio.tx_buf, txCurs);
00288     Radio::radio.tx_buf[txCurs++] = c >> 8;
00289     Radio::radio.tx_buf[txCurs++] = c;
00290 
00291     Radio::Send(txCurs, 0, 0, 0);
00292     state = STATE_ACK_WAITING;
00293 
00294     return txCurs;
00295 } // .._tx_forward()
00296 
00297 volatile us_timestamp_t prevFwdStart;
00298 
00299 void tx_forward_cb()
00300 {
00301     unsigned dur;
00302     uint8_t txlen;
00303     us_timestamp_t now;
00304 
00305     now = Radio::lpt.read_us();
00306 
00307     if (measuredIntervalSaved != 0)  // in case nothing received
00308         mbedTImeout_forwarder.attach_us(tx_forward_cb, measuredIntervalSaved);
00309 
00310     Radio::radio.tx_buf[1] = 0; //initialize flags
00311     forwardLenAckd = 0;
00312 
00313     txlen = _tx_forward();
00314 
00315     flags.mbedTImeout_forwarderStarted = 0;
00316 
00317     dur = Radio::lora_toa_us(txlen);
00318     pc.printf("\e[7mtx_forward_cb %lld", now - prevFwdStart - TX_INTERVAL_US);
00319     pc.printf(" dur%u\e[0m\r\n", dur);
00320     prevFwdStart = now;
00321 }
00322 #endif /* UNIT_ID != 0x00 */
00323 
00324 void sample_ticker_cb()
00325 {
00326     flags.sample = 1;
00327 }
00328 
00329 #else // ..UNIT_LAST:
00330 void uart_forward_cb()
00331 {
00332     if (measuredIntervalSaved != 0)  // in case nothing received
00333         mbedTImeout_forwarder.attach_us(uart_forward_cb, measuredIntervalSaved);
00334 
00335     forwardLenAckd = 0;
00336     print_payload();
00337 
00338     setupNext();
00339 
00340     flags.mbedTImeout_forwarderStarted = 0;
00341 }
00342 #endif /* UNIT_LAST */
00343 
00344 void nextRxStartCB()
00345 {
00346     unsigned us;
00347 
00348     Radio::Rx(0);
00349     rxStartAt = Radio::lpt.read_us();
00350 
00351     us = (MAX_TX_ATTEMPTS * retryInterval_us) + (MAX_TX_ATTEMPTS * TXRX_PADDING_US);
00352 
00353     pc.printf("nextRxStartCB for %uus\r\n", us);
00354 
00355 #ifndef UNIT_LAST
00356     flags.sample = 1;
00357 #endif /* UNIT_LAST */
00358 }
00359 
00360 
00361 void txDoneCB()
00362 {
00363     char str[32];
00364 
00365     Radio::Rx(0);   // receive ack
00366     stateToString(state, str);
00367     pc.printf("%s:txDone->Rx\r\n", str);
00368 }
00369 
00370 void rxDoneCB(uint8_t size, float rssi, float snr)
00371 {
00372 #if (UNIT_ID != 0x00)
00373     pkt_flags_t f;
00374     us_timestamp_t rxIrqAt = Radio::irqAt;
00375 #endif /* UNIT_ID != 0x00 */
00376     char str[32];
00377 
00378     stateToString(state, str);
00379     pc.printf("\e[33mrxDoneCB() %u rssi:%.1fdBm snr:%.1fdB %s ID:%02x\e[0m ", size, rssi, snr, str, Radio::radio.rx_buf[0]);
00380 #if (UNIT_ID != 0x00)
00381     if (state == STATE_GET_REQ) {
00382         uint8_t len;
00383         unsigned c, rxc;
00384         if (Radio::radio.rx_buf[0] != UNIT_ID-1) {
00385             pc.printf(" (not %02x)\r\n", UNIT_ID-1);
00386             return;
00387         }
00388         if (size < 4) {
00389             /* minimum: header + crc */
00390             pc.printf(" (size<4)\r\n");
00391             return;
00392         }
00393         f.octet = Radio::radio.rx_buf[1];
00394 
00395         c = crc16(Radio::radio.rx_buf, size-2);
00396         rxc = Radio::radio.rx_buf[size-2];
00397         rxc <<= 8;
00398         rxc |= Radio::radio.rx_buf[size-1];
00399         if (c != rxc) {
00400             pc.printf("\e[31mfrom%02x c:%04x rxc:%04x\e[0m\r\n", Radio::radio.rx_buf[0], c, rxc);
00401             for (unsigned n = 0; n < size; n++)
00402                 pc.printf("%02x ", Radio::radio.rx_buf[n]);
00403             pc.printf("\r\n");
00404             return;
00405         }
00406         //noRxTimeout.detach();
00407 
00408         pc.printf(" attempt%u frag%u fragLast%u ", f.bits.attempt, f.bits.fragNum, f.bits.fragLast);
00409         if (state == STATE_GET_REQ && flags.mbedTImeout_forwarderStarted == 0 && f.bits.fragLast) {
00410             us_timestamp_t now;
00411             unsigned sinceRxDone, us;
00412             mbedTImeout_forwarder.detach();
00413             now = Radio::lpt.read_us();
00414             sinceRxDone = now - rxIrqAt;
00415             us = retryInterval_us * (MAX_TX_ATTEMPTS - f.bits.attempt);
00416             int target_us = us - sinceRxDone;
00417             // tx to occur after time given for all potential retries
00418 #ifndef UNIT_LAST
00419             flags.sample = 1;   // sample from main loop, to be ready for tx_forward
00420             mbedTImeout_forwarder.attach_us(tx_forward_cb, target_us);
00421 #else
00422             mbedTImeout_forwarder.attach_us(uart_forward_cb, target_us);
00423 #endif /* UNIT_LAST */
00424             pc.printf("schedule forward %u, forwarding in %dus. sinceRxDone:%u\r\n",  MAX_TX_ATTEMPTS - f.bits.attempt, target_us, sinceRxDone);
00425             flags.mbedTImeout_forwarderStarted = 1;
00426             forwardedAt = now + target_us;
00427         }
00428 
00429         Radio::radio.tx_buf[0] = UNIT_ID;   // OK, send ACK
00430         Radio::Send(1, 0, 0, 0);
00431 
00432 
00433         if (prevFrag != f.bits.fragNum) {
00434             len = size - 4; // -4: header ... crc
00435             memcpy(forward_buf + forwardLen, Radio::radio.rx_buf+2, len);
00436             forwardLen += len;
00437 
00438             prevFrag = f.bits.fragNum;
00439         }
00440 
00441         if (f.bits.fragNum == 0) {
00442             unsigned attemptOffset = retryInterval_us * f.bits.attempt;
00443             if (rxStartAt == 0) {
00444                 pc.printf("\e[7m");
00445             }
00446             pc.printf("lastRxIrqAt:%llu measuredInterval:%llu ", lastRxIrqAt, measuredInterval);
00447             if (lastRxIrqAt != 0) {
00448                 us_timestamp_t thisMeas;
00449                 int err_;
00450                 unsigned abserr;
00451                 thisMeas = (rxIrqAt - attemptOffset) - lastRxIrqAt;
00452                 err_ = thisMeas - TX_INTERVAL_US;
00453                 if (TX_INTERVAL_US > thisMeas)
00454                     abserr = TX_INTERVAL_US - thisMeas;
00455                 else
00456                     abserr = thisMeas - TX_INTERVAL_US;
00457 
00458                 pc.printf(" this:%llu AO:%u, err_:%d ", thisMeas, attemptOffset, err_);
00459                 if (abserr < MEASURED_MAX_ERR) {
00460                     int rxPrecedency = 0;
00461                     unsigned sinceRxDone, _us_;
00462                     unsigned pktDur = Radio::lora_toa_us(size);
00463                     us_timestamp_t firstAttemptStartedAt = (rxIrqAt - attemptOffset) - pktDur;
00464 
00465                     measuredInterval = thisMeas;
00466                     _us_ = measuredInterval;
00467                     pc.printf("->%llu ", measuredInterval);
00468 
00469                     if (rxStartAt != 0) {
00470                         rxPrecedency = firstAttemptStartedAt - rxStartAt;
00471                         if (rxPrecedency > 0)
00472                             _us_ += rxPrecedency / 2;
00473                         else
00474                             _us_ += rxPrecedency;
00475                     }
00476 
00477                     _us_ -= rxStartup_us;
00478                     _us_ -= retryInterval_us; // TODO
00479                     mbedTimeout_nextRx.detach();
00480                     sinceRxDone = Radio::lpt.read_us() - rxIrqAt;
00481                     mbedTimeout_nextRx.attach_us(nextRxStartCB, _us_ - sinceRxDone);
00482                     pc.printf("nextRx:%u ao%u rxPrecedency:%d pktDur%u ri%u sinceRxDone%u ", _us_ - sinceRxDone, attemptOffset, rxPrecedency, pktDur, retryInterval_us, sinceRxDone);
00483 
00484                     if (measuredIntervalSaved == 0)
00485                         measuredIntervalSaved = measuredInterval;
00486                     else {
00487                         measuredIntervalSaved += measuredInterval;
00488                         measuredIntervalSaved /= 2;
00489                     }
00490 
00491                     rxStartAt = 0;
00492                 } else
00493                     pc.printf("\e[31mtoo-much-err\e[0m\r\n");
00494 
00495                 pc.printf("\r\n");
00496             } // ..if (lastRxIrqAt != 0)
00497 
00498             lastRxIrqAt = rxIrqAt - attemptOffset;
00499 
00500             pc.printf("\e[0m");
00501         } // ..if (f.bits.fragNum == 0)
00502 
00503     } // ..if (state == STATE_GET_REQ)
00504     else 
00505 #endif /* UNIT_ID != 0x00 */
00506 #ifndef UNIT_LAST
00507     if (state == STATE_ACK_WAITING) {
00508 
00509         if (Radio::radio.rx_buf[0] == UNIT_ID+1) {
00510             pkt_flags_t f;
00511             f.octet = Radio::radio.tx_buf[1];
00512 
00513             tickerRetry.detach();
00514             forwardLenAckd = forwardLenTransmitted;
00515             if (f.bits.fragLast) {
00516                 pc.printf("ackOk-last ");
00517 #if (UNIT_ID == 0x00)
00518                 pc.printf("->SLEEP ");
00519                 Radio::Sleep();
00520 #else
00521                 setupNext();
00522 #endif /* UNIT_ID != 0x00 */
00523             } else {
00524                 f.bits.fragNum++;
00525                 f.bits.attempt = 0;
00526                 Radio::radio.tx_buf[1] = f.octet;
00527                 flags.sample = 1;
00528                 flags.fwd = 1;  // tx_forward from main loop
00529                 pc.printf("ackOk->%u ", f.bits.fragNum);
00530             }
00531         } else 
00532             pc.printf("ack from different ID %02x\r\n", Radio::radio.rx_buf[0]);
00533     }
00534 #endif /* UNIT_LAST */
00535 
00536     {
00537         mbed_stats_cpu_t stats;
00538         mbed_stats_cpu_get(&stats);
00539         printf("canDeep:%u ", sleep_manager_can_deep_sleep());
00540         printf("Uptime: %llu ", stats.uptime / 1000);
00541         printf("Sleep time: %llu ", stats.sleep_time / 1000);
00542         printf("Deep Sleep: %llu\r\n", stats.deep_sleep_time / 1000);
00543     }
00544 
00545     pc.printf("\r\n");
00546 } // ..rxDoneCB()
00547 
00548 #if (UNIT_ID == 0x00) && !defined(UNIT_LAST)
00549 LowPowerTicker      sampleTicker, txTicker;
00550 
00551 void tx_ticker_cb(void) {
00552     unsigned c;
00553     pkt_flags_t f;
00554     message_t* mptr;
00555 
00556     tickerRetry.attach_us(retry_cb, retryInterval_us);
00557 
00558     f.bits.attempt = 0;
00559     f.bits.fragNum = 0;
00560     f.bits.fragLast = 1;
00561 
00562     Radio::Standby();
00563 
00564     txCurs = 0;
00565     Radio::radio.tx_buf[txCurs++] = UNIT_ID;
00566     Radio::radio.tx_buf[txCurs++] = f.octet;
00567 
00568     mptr = (message_t*)(Radio::radio.tx_buf + txCurs);
00569     mptr->unit_id = UNIT_ID;
00570     mptr->flags = 0x00;
00571     mptr->sample = sample;
00572 #ifdef N_SMP
00573     for (c = 0; c < N_SMP; c++)
00574         mptr->samples[c] = samples[c];
00575 #endif
00576     txCurs += sizeof(message_t);
00577 
00578     c = crc16(Radio::radio.tx_buf, txCurs);
00579     Radio::radio.tx_buf[txCurs++] = c >> 8;
00580     Radio::radio.tx_buf[txCurs++] = c;
00581 
00582     Radio::Send(txCurs, 0, 0, 0);
00583     txStartAt = Radio::lpt.read_us();
00584     state = STATE_ACK_WAITING;
00585 
00586     {
00587         mbed_stats_cpu_t stats;
00588         mbed_stats_cpu_get(&stats);
00589         pc.printf("canDeep:%u ", sleep_manager_can_deep_sleep());
00590         pc.printf("Uptime: %llu ", stats.uptime / 1000);
00591         pc.printf("Sleep time: %llu ", stats.sleep_time / 1000);
00592         pc.printf("Deep Sleep: %llu ", stats.deep_sleep_time / 1000);
00593     }
00594 
00595     pc.printf("tx_ticker_cb:%u\r\n", mptr->sample);
00596 }
00597 #endif /* UNIT_ID == 0x00 */
00598 
00599 #ifdef SX128x_H
00600 void
00601 print_radio_chip()
00602 {
00603     uint8_t buf[6];
00604     unsigned khz = 0;
00605     LoRaPktPar0_t LoRaPktPar0;
00606     LoRaPktPar1_t LoRaPktPar1;
00607     status_t st;
00608 
00609     Radio::radio.xfer(OPCODE_GET_IRQ_STATUS, 0, 3, buf);
00610     st.octet = buf[0];
00611     printf("mode:%u cmdStatus:%u irq:%02x %02x ", st.bits.chipMode, st.bits.cmdStatus, buf[1], buf[2]);
00612 
00613     LoRaPktPar0.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR0, 1);
00614     switch (LoRaPktPar0.bits.modem_bw) {
00615         case 2: khz = 200; break;
00616         case 3: khz = 400; break;
00617         case 4: khz = 800; break;
00618         case 5: khz = 1600; break;
00619     }
00620     printf("read:%uKHz sf%u\r\n", khz, LoRaPktPar0.bits.modem_sf);
00621 
00622     printf("paylen%u ", (uint8_t)Radio::radio.readReg(REG_ADDR_LORA_TX_PAYLOAD_LENGTH, 1));
00623     LoRaPktPar1.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR1, 1);
00624     printf("cr%u ", LoRaPktPar1.bits.coding_rate);
00625     if (LoRaPktPar1.bits.rxinvert_iq)
00626         printf("std ");
00627     else
00628         printf("inv ");
00629     if (LoRaPktPar1.bits.implicit_header)
00630         printf("im");
00631     else
00632         printf("ex");
00633     printf("plicit\r\n");
00634 }
00635 #elif defined(SX127x_H) /* ...SX128x_H */
00636 
00637 void
00638 print_radio_chip()
00639 {
00640 }
00641 #elif defined(SX126x_H) /* ...SX127x_H */
00642 
00643 void
00644 print_radio_chip()
00645 {
00646 }
00647 #endif
00648 
00649 void uart_rx()
00650 {
00651     char str[32];
00652 
00653     char ch = pc.getc();
00654     switch (ch) {
00655         case '+':
00656             rxStartup_us += 500;
00657             pc.printf("rxStartup_us:%u\r\n", rxStartup_us);
00658             break;
00659         case '-':
00660             if (rxStartup_us > 500)
00661                 rxStartup_us -= 500;
00662             pc.printf("rxStartup_us:%u\r\n", rxStartup_us);
00663             break;
00664         case '.':
00665             //Radio::PrintStatus();
00666             printf("UNIT_ID:%02x ", UNIT_ID);
00667             printf(" measuredInterval:%llu\r\n", measuredInterval);
00668             stateToString(state, str);
00669             printf(" %s\r\n", str);
00670             break;
00671         case 'r':
00672             flags.run ^= 1;
00673             printf("\r\nrun %u\r\n", flags.run);
00674             if (flags.run == 0) {
00675 #ifndef UNIT_LAST
00676                 tickerRetry.detach();
00677 #endif /* !UNIT_LAST */
00678                 mbedTImeout_forwarder.detach();
00679                 mbedTimeout_nextRx.detach();
00680 
00681                 Radio::Sleep();
00682             }
00683             break;
00684     } // ..switch (ch)
00685 }
00686 
00687 void radio_irq_topHalf()
00688 {
00689     flags.svc = 1;
00690 }
00691 
00692 const RadioEvents_t rev = {
00693     /* DioPin_top_half */     radio_irq_topHalf,
00694     /* TxDone_topHalf */    NULL,//txDoneCBth,
00695     /* TxDone_botHalf */    txDoneCB,
00696     /* TxTimeout  */        NULL,
00697     /* RxDone  */           rxDoneCB,
00698     /* RxTimeout  */        NULL,
00699     /* RxError  */          NULL,
00700     /* FhssChangeChannel  */NULL,
00701     /* CadDone  */          NULL
00702 };
00703 
00704 int main()
00705 {
00706     flags.run = 1;
00707     pc.baud(115200);
00708     pc.printf("\r\nreset\r\n");
00709 
00710     Radio::Init(&rev);
00711 
00712     Radio::Standby();
00713     Radio::LoRaModemConfig(BW_KHZ, SPREADING_FACTOR, 1);
00714     Radio::LoRaPacketConfig(8, false, true, false);  // preambleLen, fixLen, crcOn, invIQ
00715     Radio::SetChannel(CF_MHZ * 1000000);
00716 
00717     printf("user_button:%u\r\n", button.read());
00718     if (button.read()) {
00719         Radio::set_tx_dbm(TX_DBM);
00720         printf("PA to %ddBm\r\n", TX_DBM);
00721     } else {
00722         Radio::set_tx_dbm(PA_OFF_DBM);
00723         printf("PA off\r\n");
00724     }
00725 
00726     /* max TX length + turnaround + ACK length */
00727     retryInterval_us = Radio::lora_toa_us(MAX_TX_LENGTH) + TXRX_PADDING_US + Radio::lora_toa_us(1);
00728 #ifdef UNIT_LAST
00729     pc.printf("LAST ");
00730 #endif
00731     pc.printf("UNIT_ID:%02x retryInterval_us:%u\r\n", UNIT_ID, retryInterval_us);
00732 
00733     state = STATE_NONE;
00734 
00735 #if (UNIT_ID == 0x00) && !defined(UNIT_LAST)
00736     sampleTicker.attach_us(sample_ticker_cb, TX_INTERVAL_US);
00737     wait_us(50000);
00738     txTicker.attach_us(tx_ticker_cb, TX_INTERVAL_US);
00739 #else
00740     //Radio::PrintStatus();
00741 
00742     setupNext();
00743 
00744     measuredInterval = 0;
00745     lastRxIrqAt = 0;
00746     measuredIntervalSaved = 0;
00747 #endif /* UNIT_ID != 0x00 */
00748 
00749     /*
00750     if (sleep_manager_can_deep_sleep())
00751         sleep_manager_lock_deep_sleep();    // prevent deep sleep
00752         */
00753 
00754     for (;;) {
00755         if (pc.readable()) {
00756             uart_rx();
00757         }
00758 
00759 #ifndef UNIT_LAST
00760         if (flags.sample) {
00761             sample = ain.read_u16();
00762 #ifdef N_SMP
00763             for (c = 0; c < N_SMP; c++)
00764                 samples[c] = ain.read_u16();
00765 #endif
00766             print_radio_chip();
00767             if (flags.fwd) {
00768 #if (UNIT_ID == 0x00)
00769                 pc.printf("\e[31mID00-fwd\e[0m\r\n");
00770 #else
00771                 _tx_forward();
00772 #endif /* UNIT_ID != 0x00 */
00773                 flags.fwd = 0;
00774             }
00775 
00776             flags.sample = 0;
00777         }
00778 #endif /* UNIT_LAST */
00779 
00780         sleep_manager_sleep_auto();;
00781 
00782         if (flags.svc) {
00783             Radio::service();
00784             flags.svc = 0;
00785         }
00786 
00787     } // ..for (;;)
00788 }
00789