operate LoRa radio over I2C

Dependencies:   TimeoutAbs lib_i2c_slave_block sx12xx_hal

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 
00002 #include <mbed.h>
00003 #include "LowPowerTimeoutAbs.h"
00004 #include "radio_device.h"
00005 
00006 #define IRQ_OUT_PIN     D6
00007 
00008 #define BEACON_PRELOAD_us               500000
00009 
00010 typedef struct {
00011     uint8_t beacon_enabled : 1; // 0
00012     uint8_t beacon_guard   : 1; // 1
00013     uint8_t beacon_loaded  : 1; // 2
00014     uint8_t beacon_test    : 1; // 3
00015     uint8_t req_type       : 4; // 4,5,6,7
00016 } flags_t;
00017 
00018 const int SLAVE_ADDRESS = 0xA0;
00019 
00020 RawSerial pc(USBTX, USBRX);
00021 
00022 EventQueue queue;
00023 uint8_t skip_beacon_cnt = 0;
00024 uint16_t beaconPreambleSymbs;
00025 uint16_t preambleSymbs;
00026 unsigned beaconInterval_us;
00027 uint8_t beaconSizeBytes;
00028 /* low power timer used because hi-speed timer doesnt have crystal, and 32Khz crystal is 20ppm */
00029 LowPowerTimeoutAbs send_beaconTimer;
00030 LowPowerTimeoutAbs load_beaconTimer;
00031 uint8_t beacon_payload[4];
00032 cfg_t cfg;
00033 uint8_t get_n_rssi;
00034 
00035 volatile flags_t flags;
00036 volatile uint8_t bs;
00037 volatile uint16_t rx_slot;
00038 volatile us_timestamp_t beaconAt;
00039 volatile uint8_t blocked_cmd;
00040 
00041 DigitalOut irqOutPin(IRQ_OUT_PIN);
00042 irq_t irq;
00043 
00044 uint8_t toI2C_rx_pkt[256];
00045 volatile uint16_t toI2C_rx_pkt_idx;   // incremented by 32: will overflow 8bit
00046 
00047 int tx_pkt_len;
00048 uint8_t tx_pkt_idx;
00049 
00050 void console()
00051 {
00052     char c;
00053     if (pc.readable() != 1)
00054         return;
00055 
00056     c = pc.getc();
00057 
00058     if (c == '.') {
00059         pc.printf("beacon_guard%u ", flags.beacon_guard);
00060         pc.printf("beacon_loaded%u ", flags.beacon_loaded);
00061         pc.printf("bs:%u\r\n", bs);
00062     }
00063 }
00064 
00065 void
00066 send_beacon()
00067 {
00068     bs = 3;
00069     if (!flags.beacon_loaded)
00070         return;
00071 
00072     bs = 4;
00073     Radio::Send(beaconSizeBytes, 0, 0, 0);
00074     flags.beacon_loaded = false;
00075 }
00076 
00077 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
00078 {
00079     // The CRC calculation follows CCITT
00080     const uint16_t polynom = 0x1021;
00081     // CRC initial value
00082     uint16_t crc = 0x0000;
00083 
00084     if( buffer == NULL )
00085     {
00086         return 0;
00087     }
00088 
00089     for( uint16_t i = 0; i < length; ++i )
00090     {
00091         crc ^= ( uint16_t ) buffer[i] << 8;
00092         for( uint16_t j = 0; j < 8; ++j )
00093         {
00094             crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
00095         }
00096     }
00097 
00098     return crc;
00099 }
00100 
00101 void
00102 _load_beacon()
00103 {
00104     bool inv_iq = false;
00105     uint16_t crc;
00106 
00107     bs = 2;
00108     Radio::Standby( );
00109 
00110     if (skip_beacon_cnt > 0) {
00111         inv_iq = true;
00112         skip_beacon_cnt--;
00113     }
00114                        //    preambleLen, fixLen, crcOn, invIQ
00115     Radio::LoRaPacketConfig(beaconPreambleSymbs, true, false, inv_iq);
00116 
00117     Radio::SetFixedPayloadLength(beaconSizeBytes);
00118 
00119     Radio::radio.tx_buf[0] = beacon_payload[0];
00120     Radio::radio.tx_buf[1] = beacon_payload[1];
00121     Radio::radio.tx_buf[2] = beacon_payload[2];
00122     Radio::radio.tx_buf[3] = beacon_payload[3];
00123     //beacon_payload[0] = CMD_NONE;
00124 
00125     crc = beacon_crc(Radio::radio.tx_buf, 4);
00126     Radio::radio.tx_buf[4] = crc & 0xff;
00127     Radio::radio.tx_buf[5] = crc >> 8;
00128 
00129     flags.beacon_loaded = true;
00130 }
00131 
00132 uint16_t tim_get_current_slot()
00133 {
00134     us_timestamp_t us_until = beaconAt - send_beaconTimer.read_us();
00135     return us_until / 30000;
00136 }
00137 
00138 void load_beacon()
00139 {
00140     if (flags.beacon_enabled) {
00141         flags.beacon_guard = true;
00142         bs = 1;
00143         queue.call_in(200, _load_beacon);
00144     }
00145 }
00146 
00147 void get_random()
00148 {
00149     uint32_t r;
00150     Radio::Rx(0);
00151     wait(0.01);
00152     r = Radio::Random();
00153 
00154     irq.buf[1] = r & 0xff;
00155     r >>= 8;
00156     irq.buf[2] = r & 0xff; 
00157     r >>= 8;
00158     irq.buf[3] = r & 0xff;
00159     r >>= 8;
00160     irq.buf[4] = r & 0xff;
00161 
00162     irq.fields.flags.irq_type = IRQ_TYPE_RANDOM;
00163     irqOutPin = 1;
00164 }
00165 
00166 void cf_read()
00167 {
00168     uint32_t hz;
00169     float MHz;
00170 #ifdef SX127x_H
00171     MHz = Radio::radio.get_frf_MHz();
00172 #else
00173     MHz = Radio::radio.getMHz();
00174 #endif
00175     
00176     hz = MHz * 1000000;
00177 
00178     irq.buf[1] = hz & 0xff;
00179     hz >>= 8;
00180     irq.buf[2] = hz & 0xff; 
00181     hz >>= 8;
00182     irq.buf[3] = hz & 0xff;
00183     hz >>= 8;
00184     irq.buf[4] = hz & 0xff;
00185 
00186     irq.fields.flags.irq_type = IRQ_TYPE_CF;
00187     irqOutPin = 1;
00188 }
00189 
00190 void measure_ambient(uint8_t n_samples)
00191 {
00192     int i, acc = 0;
00193     float bg_rssi;
00194     for (i = 0; i < n_samples; i++) {
00195         int rssi = Radio::GetRssiInst();
00196         acc += rssi;
00197         wait(0.01);
00198     }
00199     bg_rssi = acc / (float)n_samples;
00200     pc.printf("bg_rssi:%.1fdBm ", bg_rssi);
00201     
00202     irq.fields.rssi = bg_rssi * 10;
00203     irq.fields.flags.irq_type = IRQ_TYPE_RSSI;
00204     irqOutPin = 1;
00205 }
00206 
00207 void txDoneCB()
00208 {
00209     if (flags.beacon_test) {
00210         flags.beacon_test = 0;
00211         return;
00212     }
00213 
00214     if (cfg.fields.flags.rxOnTxDone) {
00215                //    preambleLen, fixLen, crcOn, invIQ
00216         Radio::LoRaPacketConfig(preambleSymbs, false, true, false);
00217         
00218         Radio::Rx(0);
00219 
00220         bs = 5;
00221         if (flags.beacon_guard) {   // beacon done transmitting
00222             measure_ambient(cfg.fields.n_rssi_samples);
00223             flags.beacon_guard = false;
00224             bs = 6;
00225 
00226             beaconAt += beaconInterval_us;
00227             load_beaconTimer.attach_us(load_beacon, beaconAt - BEACON_PRELOAD_us);
00228             send_beaconTimer.attach_us(send_beacon, beaconAt);
00229         }
00230     }
00231 
00232 }
00233 
00234 void send_downlink()
00235 {
00236     if (tx_pkt_len > 0 && tx_pkt_idx >= tx_pkt_len) {
00237         Radio::Send(tx_pkt_len,
00238             cfg.fields.maxListenTime,
00239             cfg.fields.channelFreeTime,
00240             cfg.fields.rssiThresh
00241         );
00242 
00243         tx_pkt_len = 0; // packet only sent once, as requested by host
00244     }
00245 }
00246 
00247 void rxDoneCB(uint8_t size, float rssi, float snr)
00248 {
00249     if (cfg.fields.flags.rxOnTxDone) {
00250         queue.call_in(cfg.fields.downlinkOffset, send_downlink);
00251     }
00252 
00253     if (irq.fields.flags.rx_pkt == 0) {
00254         if (flags.beacon_enabled)
00255             irq.fields.rx_slot = tim_get_current_slot();
00256         else
00257             irq.fields.rx_slot = 0;
00258 
00259         irq.fields.rssi = rssi * 10;
00260         irq.fields.pkt_snr = snr;
00261         irq.fields.pkt_len = size;
00262         memcpy(toI2C_rx_pkt, Radio::radio.rx_buf, size);
00263         irq.fields.flags.rx_pkt = 1;
00264         irqOutPin = 1;
00265         pc.printf("rxlen%u snr:%.1f rssi:%.1f slot:%u\r\n", size, snr, rssi, irq.fields.rx_slot);
00266     } else {
00267         pc.printf("rx_pkt_overrun\r\n");
00268         irq.fields.flags.rx_pkt_overrun = 1;
00269     }
00270 
00271 }
00272 
00273 void tim_init()
00274 {
00275     beaconAt = send_beaconTimer.read_us() + beaconInterval_us;
00276     load_beaconTimer.attach_us(load_beacon, beaconAt - BEACON_PRELOAD_us);
00277     send_beaconTimer.attach_us(send_beacon, beaconAt);
00278 }
00279 
00280 volatile uint8_t cnt = 0;
00281 
00282 void fill_tx_buf(uint8_t cmd)     // called from isr
00283 {
00284     unsigned i;
00285 
00286     /* Master is reading from slave
00287      * Called from ISR; must return immediately */
00288 
00289     if (flags.beacon_guard && cmd >= CMD_RADIO) {
00290         blocked_cmd = cmd;
00291         return;
00292     }
00293 
00294     switch (cmd) {
00295         case CMD_TEST:
00296             for (i = 0; i < cmd_to_length[CMD_TEST]; i++)
00297                 i2c.tx_buf[i] = i + cnt;
00298             cnt++;
00299             break;
00300         case CMD_TEST32:
00301             for (i = 0; i < cmd_to_length[CMD_TEST32]; i++)
00302                 i2c.tx_buf[i] = i + cnt;
00303             cnt++;
00304             break;
00305         case CMD_RX_PAYLOAD:
00306             memcpy(i2c.tx_buf, toI2C_rx_pkt+toI2C_rx_pkt_idx, sizeof(i2c.tx_buf));
00307 
00308             toI2C_rx_pkt_idx += cmd_to_length[CMD_RX_PAYLOAD];
00309             if (toI2C_rx_pkt_idx >= irq.fields.pkt_len) {
00310                 irq.fields.pkt_len = 0;
00311                 irq.fields.flags.rx_pkt = 0;
00312                 if (irq.buf[0] == 0)
00313                     irqOutPin = 0;
00314             }
00315             break;
00316         case CMD_SKIP_BEACONS:
00317             i2c.tx_buf[0] = skip_beacon_cnt;
00318             break;
00319         case CMD_CURRENT_SLOT:
00320             {
00321                 uint16_t *u16ptr = (uint16_t*)i2c.tx_buf;
00322                 *u16ptr = tim_get_current_slot();
00323             }
00324             break;
00325         case CMD_REQ_RANDOM:
00326             flags.req_type = IRQ_TYPE_RANDOM;
00327             break;
00328         case CMD_IRQ:
00329             if (irq.fields.flags.rx_pkt)
00330                 toI2C_rx_pkt_idx = 0;   // packet reading expected to start
00331 
00332             for (i = 0; i < cmd_to_length[CMD_IRQ]; i++)
00333                 i2c.tx_buf[i] = irq.buf[i];
00334 
00335             irq.fields.flags.rx_pkt_overrun = 0;
00336             irq.fields.flags.irq_type = 0;
00337             if (irq.buf[0] == 0)
00338                 irqOutPin = 0;
00339 
00340             break;
00341     }
00342 
00343 } // ..fill_tx_buf()
00344 
00345 void service_i2c_write(uint8_t cmd, uint8_t len, const uint8_t* req)
00346 {
00347     uint32_t u32;
00348     uint8_t s8;
00349 
00350     if (flags.beacon_guard && cmd >= CMD_RADIO) {
00351         blocked_cmd = cmd;
00352         return;
00353     }
00354 
00355     switch (cmd) {
00356         case CMD_TEST:
00357         case CMD_TEST32:
00358             pc.printf("test:");
00359             for (s8 = 0; s8 < cmd_to_length[cmd]; s8++)
00360                 pc.printf("%02x ", req[s8]);
00361             pc.printf("\r\n");
00362             break;
00363         case CMD_CFHZ_REQ:
00364             flags.req_type = IRQ_TYPE_CF;
00365             break;
00366         case CMD_FSK_MODEM_CFG_REQ:
00367             flags.req_type = IRQ_TYPE_FSK_MODEM;
00368             break;
00369         case CMD_FSK_PKT_CFG_REQ:
00370             flags.req_type = IRQ_TYPE_FSK_PKT;
00371             break;
00372         case CMD_FSK_SYNC_REQ:
00373             flags.req_type = IRQ_TYPE_FSK_SYNC;
00374             break;
00375         case CMD_TXDBM_REQ:
00376             flags.req_type = IRQ_TYPE_TXDBM;
00377             break;
00378         case CMD_LORA_MODEM_CFG_REQ:
00379             flags.req_type = IRQ_TYPE_LORA_MODEM;
00380             break;
00381         case CMD_LORA_PKT_CFG_REQ:
00382             flags.req_type = IRQ_TYPE_LORA_PKT;
00383             break;
00384         case CMD_OPMODE_REQ:
00385             flags.req_type = IRQ_TYPE_OPMODE;
00386             break;
00387         case CMD_RADIO_RESET:
00388             load_beaconTimer.detach();
00389             send_beaconTimer.detach();
00390             flags.beacon_enabled = 0;
00391             radio_reset();
00392             break;
00393         case CMD_CFHZ_WRITE:
00394             u32 = req[3];
00395             u32 <<= 8;
00396             u32 |= req[2];
00397             u32 <<= 8;
00398             u32 |= req[1];
00399             u32 <<= 8;
00400             u32 |= req[0];
00401             pc.printf("setCh %luhz\r\n", u32);
00402             Radio::SetChannel(u32);
00403             break;
00404         case CMD_TXDBM_WRITE:
00405             s8 = req[0];
00406             Radio::set_tx_dbm(s8);
00407             pc.printf("set tx dBm:%d\r\n", s8);
00408             break;
00409         case CMD_LORA_MODEM_CFG_WRITE:
00410             {
00411                 uint8_t sf, cr;
00412 
00413                 u32 = req[1];
00414                 u32 <<= 8;
00415                 u32 |= req[0];
00416                 pc.printf("(%04lx) ", u32);
00417                 sf = req[2];
00418                 cr = req[3];
00419                 pc.printf("modemcfg %luKhz sf%u cr%u\r\n", u32, sf, cr);
00420                 Radio::LoRaModemConfig(u32, sf, cr);
00421             }
00422             break;
00423         case CMD_RX_START:
00424             u32 = req[3];
00425             u32 <<= 8;
00426             u32 |= req[2];
00427             u32 <<= 8;
00428             u32 |= req[1];
00429             u32 <<= 8;
00430             u32 |= req[0];
00431             Radio::Rx(u32);
00432             pc.printf("rx(%lu)\r\n", u32);
00433             break;
00434         case CMD_LORA_PKT_CFG_WRITE:
00435             {
00436                 pktcfg_t pktcfg;
00437                 u32 = req[1];
00438                 u32 <<= 8;
00439                 u32 |= req[0];
00440                 preambleSymbs = u32;
00441                 pktcfg.octet = req[2];
00442                 pc.printf("pktcfg pre%lu fixlen%u crc%u inv%u\r\n", u32, pktcfg.bits.fixLen, pktcfg.bits.crcOn, pktcfg.bits.invIQ);
00443                 Radio::LoRaPacketConfig(u32, pktcfg.bits.fixLen, pktcfg.bits.crcOn, pktcfg.bits.invIQ);
00444             }
00445             break;
00446         case CMD_BEACON_CFG_WRITE:
00447             {   
00448                 us_timestamp_t txStartAt;
00449 
00450                 u32 = req[1];
00451                 u32 <<= 8;
00452                 u32 |= req[0];
00453                 pc.printf("bi%lu ", u32);
00454                 beaconInterval_us = u32 * 1000000;
00455                 pc.printf("{%u} ", beaconInterval_us);
00456 
00457                 u32 = req[3];
00458                 u32 <<= 8;
00459                 u32 |= req[2];
00460                 pc.printf("ps%lu ", u32);
00461                 beaconPreambleSymbs = u32;
00462 
00463                 beaconSizeBytes = req[4];
00464                 pc.printf("len%u\r\n", beaconSizeBytes);
00465 
00466                 if (beaconInterval_us > 0) {
00467                     _load_beacon();
00468                     send_beacon();
00469                     txStartAt = Radio::lpt.read_us();
00470                     flags.beacon_test = 1;
00471                     while (flags.beacon_test)
00472                         Radio::service();
00473 
00474                     u32 = Radio::irqAt - txStartAt;
00475                     pc.printf("beaconDur:%lu, 0x%lx\r\n", u32, u32);
00476 
00477                     tim_init();
00478                     flags.beacon_enabled = 1;
00479 
00480                     irq.buf[1] = u32 & 0xff;
00481                     u32 >>= 8;
00482                     irq.buf[2] = u32 & 0xff; 
00483                     u32 >>= 8;
00484                     irq.buf[3] = u32 & 0xff;
00485                     u32 >>= 8;
00486                     irq.buf[4] = u32 & 0xff;
00487                     irq.fields.flags.irq_type = IRQ_TYPE_BEACON_DUR;
00488                     //pc.printf("BDirq.buf[0]:%02x\r\n", irq.buf[0]);
00489                     irqOutPin = 1;
00490                 } else {
00491                     load_beaconTimer.detach();
00492                     send_beaconTimer.detach();
00493                     flags.beacon_enabled = 0;
00494                 }
00495             }
00496             break;
00497         case CMD_BEACON_PAYLOAD:
00498             beacon_payload[0] = req[0];
00499             beacon_payload[1] = req[1];
00500             beacon_payload[2] = req[2];
00501             beacon_payload[3] = req[3];
00502             break;
00503         case CMD_CFG:
00504             memcpy(cfg.buf, req, sizeof(cfg_t));
00505             pc.printf("cfg %u\r\n", cfg.fields.n_rssi_samples);
00506             break;
00507         case CMD_STANDBY:
00508             Radio::Standby();
00509             break;
00510         case CMD_PUBLIC_NET:
00511             pc.printf("pubnet%02x\r\n", req[0]);
00512             Radio::SetPublicNetwork(req[0] == 0 ? false : true);
00513             break;
00514         case CMD_MAX_PAYLEN_WRITE:
00515             pc.printf("maxpay%02x\r\n", req[0]);
00516             Radio::SetRxMaxPayloadLength(req[0]);
00517             break;
00518         case CMD_TX_BUF_START:
00519             if (cfg.fields.flags.rxOnTxDone) {
00520                 /* turn off receiver in preparation for downlink */
00521                 Radio::Standby();   
00522 
00523                 //                         preambleLen, fixLen, crcOn, invIQ
00524                 Radio::LoRaPacketConfig(preambleSymbs, false, false, true);
00525             }
00526 
00527             tx_pkt_len = req[0];
00528             memcpy(Radio::radio.tx_buf, req+1, 31);
00529             tx_pkt_idx = 31;
00530             break;
00531         case CMD_TX_BUF:
00532             {
00533                 uint8_t len = 32;
00534                 uint8_t end = (tx_pkt_idx + 32) & 0xff;
00535                 if (end < 32)
00536                     len -= end;
00537                 memcpy(Radio::radio.tx_buf + tx_pkt_idx, req, len);
00538                 tx_pkt_idx += len;
00539             }
00540             break;
00541         case CMD_RSSI_REQ:
00542             get_n_rssi = req[0];
00543             break;
00544         case CMD_SEND:
00545             Radio::Send(tx_pkt_len,
00546                 cfg.fields.maxListenTime,
00547                 cfg.fields.channelFreeTime,
00548                 cfg.fields.rssiThresh
00549             );
00550             break;
00551         case CMD_SKIP_BEACONS:
00552             skip_beacon_cnt = req[0];
00553             break;
00554         case CMD_LORA_SYMBTO_WRITE: // 1  byte
00555             Radio::SetLoRaSymbolTimeout(req[0]);
00556             break;
00557         case CMD_FSK_MODEM_CFG_WRITE: // 10bytes
00558             {
00559                 uint32_t bps, fdev_hz;
00560                 uint16_t khz_bw;
00561                 u32 = req[3];
00562                 u32 <<= 8;
00563                 u32 |= req[2];
00564                 u32 <<= 8;
00565                 u32 |= req[1];
00566                 u32 <<= 8;
00567                 u32 |= req[0];
00568                 bps = u32;
00569 
00570                 u32 = req[5];
00571                 u32 <<= 8;
00572                 u32 |= req[4];
00573                 khz_bw = u32;
00574 
00575                 u32 = req[9];
00576                 u32 <<= 8;
00577                 u32 |= req[8];
00578                 u32 <<= 8;
00579                 u32 |= req[7];
00580                 u32 <<= 8;
00581                 u32 |= req[6];
00582                 fdev_hz = u32;
00583                 Radio::GFSKModemConfig(bps, khz_bw, fdev_hz);
00584             }
00585             break;
00586         case CMD_FSK_PKT_CFG_WRITE: // 4 bytes
00587             u32 = req[1];
00588             u32 <<= 8;
00589             u32 |= req[0];
00590             Radio::GFSKPacketConfig(u32, req[2], req[3]);
00591             break;
00592         case CMD_FSK_SYNC_WRITE:
00593             /* TODO */
00594             break;
00595 #ifdef DEBUG_SMBUS
00596         case CMD_ISR:
00597             pc.printf("i%02x ", req[0]);    // lsbyte of I2C_ISR
00598             break;
00599         case CMD_STOPF:
00600             pc.printf("STOPF\r\n");
00601             break;
00602         case CMD_AF:
00603             pc.printf("AF%u ", req[0]); // req[0] is dma tx cndtr
00604             break;
00605 #endif /* DEBUG_SMBUS */
00606         case CMD_BUSERR:
00607             pc.printf("BUSERR%u\r\n", req[0]);
00608             break;
00609         /* failures: */
00610         case CMD_ARLO:
00611             pc.printf("ARLO%u,%u\r\n", toI2C_rx_pkt_idx, req[0]); // req[0] tx_cndtr
00612             break;
00613         case CMD_TIMEOUT:
00614             pc.printf("TIMEOUT(tx%u,rx%u)\r\n", req[0], req[1]);    // req[0] tx_cndtr
00615             break;
00616         default:
00617             pc.printf("??%02x??\r\n", cmd);
00618             break;
00619     } // ..switch (cmd)
00620 
00621 } // ..service_i2c_write()
00622 
00623 const RadioEvents_t rev = {
00624     /* Dio0_top_half */     NULL,
00625     /* TxDone_topHalf */    NULL,
00626     /* TxDone_botHalf */    txDoneCB,
00627     /* TxTimeout  */        NULL,
00628     /* RxDone  */           rxDoneCB,
00629     /* RxTimeout  */        NULL,
00630     /* RxError  */          NULL,
00631     /* FhssChangeChannel  */NULL,
00632     /* CadDone  */          NULL
00633 };
00634 
00635 int main()
00636 {
00637     Thread eventThread(osPriorityNormal, 512);
00638     int res;
00639 
00640     pc.baud(115200);
00641     pc.printf("\r\nreset\r\n");
00642 
00643     Radio::Init(&rev);
00644     radio_device_init();
00645 
00646     res = smbus_init(I2C_SDA, I2C_SCL, SLAVE_ADDRESS);
00647     pc.printf("%d = smbus_init()\r\n", res);
00648     if (res < 0) {
00649         for (;;) asm("nop");
00650     }
00651 
00652     eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
00653 
00654     while (1) {
00655         if (i2c.c_overrun) {
00656             pc.printf("c_overrun\r\n");
00657             for (;;) asm("nop");
00658         }
00659 
00660         service_i2c();
00661         console();
00662 
00663         if (get_n_rssi > 0) {
00664             measure_ambient(get_n_rssi);
00665             get_n_rssi = 0;
00666         }
00667 
00668         if (flags.req_type != IRQ_TYPE_PKT) {
00669             switch (flags.req_type) {
00670                 case IRQ_TYPE_CF:
00671                     cf_read();
00672                     break;
00673                 case IRQ_TYPE_RANDOM:
00674                     get_random();
00675                     break;
00676                 case IRQ_TYPE_FSK_MODEM:
00677                     get_fsk_modem();
00678                     break;
00679                 case IRQ_TYPE_FSK_PKT:
00680                     get_fsk_packet();
00681                     break;
00682                 case IRQ_TYPE_FSK_SYNC:
00683                     get_fsk_sync();
00684                     break;
00685                 case IRQ_TYPE_TXDBM:
00686                     get_tx_dbm();
00687                     break;
00688                 case IRQ_TYPE_LORA_MODEM:
00689                     get_lora_modem();
00690                     break;
00691                 case IRQ_TYPE_LORA_PKT:
00692                     get_lora_packet();
00693                     break;
00694                 case IRQ_TYPE_OPMODE:
00695                     get_opmode();
00696                     break;
00697             } // ..switch (flags.req_type)
00698             flags.req_type = IRQ_TYPE_PKT;
00699         }
00700 
00701         if (blocked_cmd) {
00702             pc.printf("blocked_cmd:%02x\r\n", blocked_cmd);
00703             blocked_cmd = 0;
00704         }
00705 
00706         Radio::service();
00707     } // ..while (1)
00708 }
00709