wayne roberts / Mbed OS utility_sx12xx
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers radio_lr1110.cpp Source File

radio_lr1110.cpp

00001 #include "radio.h"
00002 #ifdef SX1265_H 
00003 
00004 SPI spi(D11, D12, D13); // mosi, miso, sclk
00005                    //spi, nss, busy, dio9, nreset
00006 SX1265 Radio::radio(spi, D7, D3, D5, A0, 0x3ffffcf);
00007 
00008 #define DIO_en_IDX        0
00009 #define DIO_stby_IDX      1
00010 #define DIO_rx_IDX        2
00011 #define DIO_tx_IDX        3
00012 #define DIO_txhp_IDX      4
00013 #define DIO_gnss_IDX      6
00014 #define DIO_wifi_IDX      7
00015 
00016 #define DIO5_BIT         0x01
00017 #define DIO6_BIT         0x02
00018 #define DIO7_BIT         0x04
00019 #define DIO8_BIT         0x08
00020 #define DIO10_BIT        0x10
00021 
00022 uint8_t dioBuf[8];
00023 uint8_t Radio::gfsk_pp_buf[9];
00024 uint8_t Radio::gfsk_mp_buf[10];
00025 uint8_t Radio::lora_pp_buf[6];
00026 uint8_t Radio::lora_mp_buf[4];
00027 const RadioEvents_t* Radio::RadioEvents;
00028 uint8_t Radio::pktType;
00029 uint8_t Radio::tx_param_buf[2];
00030 uint8_t Radio::pa_config_buf[4];
00031 unsigned Radio::recalCnt;
00032 uint32_t gfsk_crc_initValue;
00033 uint32_t gfsk_crc_Poly;
00034 
00035 uint8_t wifiScan_buf[9];
00036 uint8_t gnssAutonomous_buf[9];
00037 uint8_t gnssAssisted_buf[7];
00038 bool wifiResultFormatBasic;
00039 uint8_t tcxo_buf[5];
00040 
00041 void Radio::hw_reset()
00042 {
00043     radio.hw_reset();
00044     //radio.enable_default_irqs();
00045     initRfSwDIO();
00046 }
00047 
00048 void Radio::initRfSwDIO()
00049 {
00050 /* antenna truth table
00051  * V1    V2    port
00052  *  0     0    shutdown
00053  *  1     0    J2   rx RFI
00054  *  0     1    J1   HP tx RFO
00055  *  1     1    J3   LP tx RFO
00056  * DIO5  DIO6
00057  * */
00058     dioBuf[  DIO_en_IDX] = DIO5_BIT | DIO6_BIT;
00059     dioBuf[DIO_stby_IDX] = 0;
00060     dioBuf[  DIO_rx_IDX] = DIO5_BIT;
00061     dioBuf[  DIO_tx_IDX] = DIO5_BIT | DIO6_BIT;
00062     dioBuf[DIO_txhp_IDX] = DIO6_BIT;
00063     dioBuf[DIO_gnss_IDX] = 0;
00064     dioBuf[DIO_wifi_IDX] = 0;
00065     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
00066 }
00067 
00068 unsigned Radio::my_round(float x)
00069 {
00070     if (x >= 0)
00071         return (unsigned) (x+0.5);
00072     return (unsigned) (x-0.5);
00073 }
00074 
00075 void Radio::readChip()
00076 {
00077     uint32_t u32;
00078     {
00079         txParamsB_t txpb;   // txpb.bits.PaSel
00080         txParamsC_t txpc;
00081         radio.memRegRead(REG_ADDR_TX_PARAMS_C, 1, &txpc.dword);
00082         tx_param_buf[1] = txpc.bits.pa_ramp_time;
00083 
00084         radio.memRegRead(REG_ADDR_TX_PARAMS_B, 1, &txpb.dword);
00085         if (txpb.bits.PaSel)
00086             tx_param_buf[0] = txpc.bits.tx_dbm - 9;
00087         else
00088             tx_param_buf[0] = txpc.bits.tx_dbm - 17;
00089     }
00090 
00091     radio.GetPaConfig(pa_config_buf);
00092 
00093     {
00094         dioEnable_t dio;
00095         radio.memRegRead(REG_ADDR_DIO10, 1, &dio.dword);
00096         if (dio.bits.enable)
00097             dioBuf[DIO_en_IDX] |= DIO10_BIT;
00098         else
00099             dioBuf[DIO_en_IDX] &= ~DIO10_BIT;
00100 
00101         radio.memRegRead(REG_ADDR_DIO8, 1, &dio.dword);
00102         if (dio.bits.enable)
00103             dioBuf[DIO_en_IDX] |= DIO8_BIT;
00104         else
00105             dioBuf[DIO_en_IDX] &= ~DIO8_BIT;
00106 
00107         radio.memRegRead(REG_ADDR_DIO7, 1, &dio.dword);
00108         if (dio.bits.enable)
00109             dioBuf[DIO_en_IDX] |= DIO7_BIT;
00110         else
00111             dioBuf[DIO_en_IDX] &= ~DIO7_BIT;
00112 
00113         radio.memRegRead(REG_ADDR_DIO6, 1, &dio.dword);
00114         if (dio.bits.enable)
00115             dioBuf[DIO_en_IDX] |= DIO6_BIT;
00116         else
00117             dioBuf[DIO_en_IDX] &= ~DIO6_BIT;
00118 
00119         radio.memRegRead(REG_ADDR_DIO5, 1, &dio.dword);
00120         if (dio.bits.enable)
00121             dioBuf[DIO_en_IDX] |= DIO5_BIT;
00122         else
00123             dioBuf[DIO_en_IDX] &= ~DIO5_BIT;
00124     }
00125 
00126     {
00127         gfskConfig4_t cfg4;
00128         gfskConfig2_t cfg2;
00129         gfskConfig1_t cfg1;
00130         gfskConfig3_t cfg3;
00131         gfskConfig5_t cfg5;
00132 
00133         radio.memRegRead(REG_ADDR_GFSK_CFG5, 1, &cfg5.dword);
00134         gfsk_pp_buf[8] = cfg5.bits.whitening_enable;
00135 
00136         if (cfg5.bits.crc_off)
00137             gfsk_pp_buf[7] |= 1;
00138         else
00139             gfsk_pp_buf[7] &= ~1;
00140 
00141         if (cfg5.bits.crc_size)
00142             gfsk_pp_buf[7] |= 2;
00143         else
00144             gfsk_pp_buf[7] &= ~2;
00145 
00146         if (cfg5.bits.crc_invert)
00147             gfsk_pp_buf[7] |= 4;
00148         else
00149             gfsk_pp_buf[7] &= ~4;
00150 
00151         radio.memRegRead(REG_ADDR_GFSK_PAYLOAD_LENGTH_A, 1, &u32);
00152         gfsk_pp_buf[6] = u32 & 0xff;
00153 
00154         radio.memRegRead(REG_ADDR_GFSK_PAYLOAD_LENGTH_B, 1, &cfg4.dword);
00155         gfsk_pp_buf[4] = cfg4.bits.addr_comp;
00156         if (cfg4.bits.payload_length != gfsk_pp_buf[6])
00157             log_printf("length_mismatch_%02x_%02x\r\n", cfg4.bits.payload_length, gfsk_pp_buf[6]);
00158 
00159         radio.memRegRead(REG_ADDR_GFSK_CFG3, 1, &cfg3.dword);
00160         gfsk_pp_buf[5] = cfg3.bits.variable_length;
00161 
00162         radio.memRegRead(REG_ADDR_GFSK_CFG2, 1, &cfg2.dword);
00163         gfsk_pp_buf[3] = cfg2.bits.sync_word_length;
00164 
00165         radio.memRegRead(REG_ADDR_GFSK_CFG1, 1, &cfg1.dword);
00166         radio.to_big_endian16(cfg1.bits.preamble_length, gfsk_pp_buf);
00167         if (cfg1.bits.preamble_det_enable)
00168             gfsk_pp_buf[2] = cfg1.bits.preamble_det_len;
00169         else
00170             gfsk_pp_buf[2] = 0;
00171 
00172         {
00173             unsigned hz;
00174             radio.memRegRead(REG_ADDR_GFSK_BITRATE, 1, &u32);
00175             hz = GFSK_BITRATE_NUMERATOR / u32;
00176             radio.to_big_endian32(hz, gfsk_mp_buf);
00177         }
00178         //gfsk_mp_buf[4] = bt;
00179         //gfsk_mp_buf[5] = bwf;
00180         //gfsk_mp_buf[6,7,8,9] = fdevHz;
00181         {
00182             unsigned hz;
00183             radio.memRegRead(REG_ADDR_GFSK_FDEV, 1, &u32);
00184             hz = my_round(u32 * FREQ_STEP);
00185             radio.to_big_endian32(hz, gfsk_mp_buf+6);
00186         }
00187 
00188         radio.memRegRead(REG_ADDR_GFSK_CRC_INIT, 1, &gfsk_crc_initValue);
00189         radio.memRegRead(REG_ADDR_GFSK_CRC_POLY, 1, &gfsk_crc_Poly);
00190     }
00191 
00192     /**********************************************/
00193     {
00194         uint16_t u16;
00195         loraConfig0_t cfg0;
00196         loraConfigB_t cfgb;
00197         loraConfigC_t cfgc;
00198 
00199         radio.GetLoRaModulationParameters(lora_mp_buf);
00200 
00201         radio.memRegRead(REG_ADDR_LORA_CONFIGC, 1, &cfgc.dword);
00202         u16 = cfgc.bits.preamble_length;
00203         lora_pp_buf[1] = u16 & 0xff;
00204         u16 >>= 8;
00205         lora_pp_buf[0] = u16;
00206 
00207         radio.memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
00208         lora_pp_buf[2] = cfg0.bits.implicit_header;
00209         lora_pp_buf[3] = cfg0.bits.payload_length;
00210         lora_pp_buf[4] = cfg0.bits.crc_on;
00211 
00212         radio.memRegRead(REG_ADDR_LORA_CONFIGB, 1, &cfgb.dword);
00213         lora_pp_buf[5] = cfgb.bits.invertIQ;
00214 
00215     }
00216 
00217     {   /* wifi scan defaults */
00218         unsigned chanmask = 0x0421;
00219         unsigned timeout = 0x0046;
00220 
00221         wifiScan_buf[0] = 0x01; // wifi type
00222         wifiScan_buf[2] = chanmask; // chanmask-lo
00223         chanmask >>= 8;
00224         wifiScan_buf[1] = chanmask; // chanmask-hi
00225         wifiScan_buf[3] = 0x02; // acqMode
00226         wifiScan_buf[4] = 0x0a; // NbMaxRes
00227         wifiScan_buf[5] = 0x06; // NbScanPerChan
00228         wifiScan_buf[7] = timeout; // Timeout-lo
00229         timeout >>= 8;
00230         wifiScan_buf[6] = timeout; // Timeout-hi
00231         wifiScan_buf[8] = 0x00; // AbortOnTimeout
00232     }
00233 
00234 }
00235 
00236 void Radio::clearIrqFlags()
00237 {
00238     uint8_t buf[4];
00239     buf[0] = buf[1] = buf[2] = buf[3] = 0xff;
00240     radio.xfer(OPCODE_CLEAR_IRQ, 4, 0, buf);
00241 }
00242 
00243 uint8_t Radio::get_payload_length()
00244 {
00245     uint8_t pktType = radio.getPacketType();
00246 
00247     if (pktType == PACKET_TYPE_LORA) {
00248         unsigned foo;
00249         loraConfig0_t cfg0;
00250         radio.memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
00251         foo = cfg0.dword;
00252         foo >>= 24;
00253         lora_pp_buf[3] = cfg0.bits.payload_length;
00254         return cfg0.bits.payload_length;
00255     } else if (pktType == PACKET_TYPE_GFSK) {
00256         uint32_t u32;
00257         /* TODO: which is rx payloadLength vs tx payloadLength */
00258         //gfskConfig4_t cfg4;
00259         radio.memRegRead(REG_ADDR_GFSK_PAYLOAD_LENGTH_A, 1, &u32);
00260         gfsk_pp_buf[6] = u32 & 0xff;
00261         /*radio.memRegRead(REG_ADDR_GFSK_PAYLOAD_LENGTH_B, 1, buf);
00262         cfg4.dword = radio.from_big_endian32(buf);*/
00263 
00264         /*
00265         if ((rb & 0xff) != cfg4.bits.payload_length) {
00266             log_printf("gfsk payload length A:%u B:%u\r\n", rb & 0xff, cfg4.bits.payload_length);
00267             // todo: which is tx-length vs rx-length
00268         }
00269         */
00270 
00271         return u32 & 0xff;
00272     }
00273     return 0;
00274 }
00275 
00276 bool Radio::tx_payload_length_write(const char* txt)
00277 {
00278     unsigned len;
00279     sscanf(txt, "%u", &len);
00280     set_payload_length(len);
00281     return false;
00282 }
00283 
00284 unsigned Radio::read_register(unsigned addr)
00285 {
00286     uint32_t u32;
00287     radio.memRegRead(addr, 1, &u32);
00288     return u32;
00289 }
00290 
00291 void Radio::write_register(unsigned addr, unsigned val)
00292 {
00293     stat_t stat;
00294     uint8_t buf[8];
00295     radio.to_big_endian32(addr, buf);
00296     radio.to_big_endian32(val, buf);
00297     stat.word = radio.xfer(OPCODE_WRITEREGMEM32, 8, 0, buf);
00298     print_stat(stat);
00299 }
00300 
00301 void Radio::txTimeout_print()
00302 {
00303     float sec = radio.txTimeout / 32768.0;
00304     printf("%.3f", sec);
00305 }
00306 
00307 bool Radio::txTimeout_write(const char *txt)
00308 {
00309     float sec;
00310     if (sscanf(txt, "%f", &sec) == 1) {
00311         radio.txTimeout = sec * 32768;
00312         log_printf("txTimeout:%u\r\n", radio.txTimeout);
00313     }
00314     return false;
00315 }
00316 
00317 const value_item_t Radio::txTimeout_item = { _ITEM_VALUE, 6, txTimeout_print, txTimeout_write};
00318 
00319 bool regulator_read()
00320 {
00321     regulatorMode_t rm;
00322     Radio::radio.memRegRead(REG_ADDR_REGULATOR_MODE, 1, &rm.dword);
00323     return rm.bits.dcdc_en;
00324 }
00325 
00326 bool regulator_push()
00327 {
00328     uint8_t buf = regulator_read() ? 0 : 1;
00329     Radio::radio.xfer(OPCODE_SET_REGULATOR_MODE, 1, 0, &buf);
00330     return buf == 1;
00331 }
00332 
00333 const toggle_item_t regulator_item = { _ITEM_TOGGLE,
00334     " LDO ",
00335     "DC-DC",
00336     regulator_read,
00337     regulator_push
00338 };
00339 
00340 const char* const tcxovolts_strs[] 
00341 {
00342     "1.6", // 0
00343     "1.8", // 1
00344     "1.8", // 2
00345     "2.2", // 3
00346     "2.4", // 4
00347     "2.7", // 5
00348     "3.0", // 6
00349     "3.3", // 7
00350     NULL
00351 };
00352 
00353 unsigned tcxovolts_read(bool for_writing)
00354 {
00355     tcxo_t tcxo;
00356     Radio::radio.memRegRead(REG_ADDR_TCXO, 1, &tcxo.dword);
00357     return tcxo.bits.volts;
00358 }
00359 
00360 menuMode_e tcxovolts_write(unsigned sidx)
00361 {
00362     tcxo_buf[0] = sidx;
00363     Radio::radio.xfer(OPCODE_SET_TCXO_MODE, 5, 0, tcxo_buf);
00364     return MENUMODE_REDRAW;
00365 }
00366 
00367 const dropdown_item_t tcxo_volts_item = { _ITEM_DROPDOWN, tcxovolts_strs, tcxovolts_strs, tcxovolts_read, tcxovolts_write};
00368 
00369 void tcxo_delay_print()
00370 {
00371     unsigned ticks = tcxo_buf[1];
00372     ticks <<= 8;
00373     ticks |= tcxo_buf[2];
00374     ticks <<= 8;
00375     ticks |= tcxo_buf[3];
00376     printf("%.1f", ticks / 32.768);
00377 }
00378 
00379 bool tcxo_delay_write(const char *txt)
00380 {
00381     float ms;
00382     if (sscanf(txt, "%f", &ms) == 1) {
00383         unsigned ticks = ms * 32.768;
00384         Radio::radio.to_big_endian24(ticks, tcxo_buf+1);
00385         Radio::radio.xfer(OPCODE_SET_TCXO_MODE, 5, 0, tcxo_buf);
00386     }
00387     return false;
00388 }
00389 
00390 const value_item_t tcxo_delay_item = { _ITEM_VALUE, 5, tcxo_delay_print, tcxo_delay_write};
00391 
00392 void recalibrate_print() { }
00393 
00394 bool recalibrate_write(const char *txt)
00395 {
00396     unsigned bits;
00397     uint8_t buf = 0;
00398     if (sscanf(txt, "%x", &bits) == 1) {
00399         buf = bits;
00400     }
00401     Radio::radio.xfer(OPCODE_CALIBRATE, 1, 0, &buf);
00402     return false;
00403 }
00404 
00405 const value_item_t recalibrate_item = { _ITEM_VALUE, 5, recalibrate_print, recalibrate_write};
00406 
00407 
00408 void Radio::rxBuffer_push()
00409 {
00410     uint8_t buf[4];
00411     stat_t stat;
00412     stat.word = radio.xfer(OPCODE_GET_RX_BUFFER_STATUS, 0, 0, NULL);
00413     stat.word = radio.xfer(0x0000, 0, 2, buf);
00414     log_printf("rxBufferStatus:%s\r\n", radio.cmdStatus_toString(stat.bits.cmdStatus));
00415     if (stat.bits.cmdStatus == CMD_DAT) {
00416         uint8_t len = buf[0];
00417         uint8_t offset = buf[1];
00418         buf[0] = offset;
00419         buf[1] = len;
00420         stat.word = radio.xfer(OPCODE_READ_BUFFER8, 2, 0, NULL);
00421         log_printf("len%u ofs:%u readBuffer8cmd:%s\r\n", len, offset, radio.cmdStatus_toString(stat.bits.cmdStatus));
00422         stat.word = radio.xfer(0x0000, 0, len, radio.rx_buf);
00423         log_printf("readBuffer8resp:%s\r\n", radio.cmdStatus_toString(stat.bits.cmdStatus));
00424         printRxPkt(len);
00425     }
00426 }
00427 
00428 const button_item_t Radio::rxBufferStatus_item = { _ITEM_BUTTON, "rxbufStat", rxBuffer_push};
00429 
00430 void Radio::getStats_push(void)
00431 {
00432     uint8_t buf[8];
00433     stat_t stat;
00434     stat.word = radio.xfer(OPCODE_GET_STATS, 0, 0, NULL);
00435     stat.word = radio.xfer(0x0000, 0, 8, buf);
00436     if (stat.bits.cmdStatus == CMD_DAT) {
00437         uint8_t pktType = radio.getPacketType();
00438         uint16_t data1, data2, nbPktCrcErr, nbPktRx = buf[0];
00439         nbPktRx <<= 8;
00440         nbPktRx |= buf[1];
00441         nbPktCrcErr = buf[2];
00442         nbPktCrcErr <<= 8;
00443         nbPktCrcErr |= buf[3];
00444         data1 = buf[4];
00445         data1 <<= 8;
00446         data1 |= buf[5];
00447         data2 = buf[6];
00448         data2 <<= 8;
00449         data2 |= buf[7];
00450         if (pktType == PACKET_TYPE_LORA) {
00451             log_printf("nbPktRx:%u nbPktCrcErr:%u hdrErr:%u falseSync:%u\r\n", nbPktRx, nbPktCrcErr, data1, data2);
00452         } else if (pktType == PACKET_TYPE_GFSK) {
00453             log_printf("nbPktRx:%u nbPktCrcErr:%u nbLenErr:%u\r\n", nbPktRx, nbPktCrcErr, data1);
00454         }
00455     }
00456 }
00457 
00458 const button_item_t Radio::getStats_item = { _ITEM_BUTTON, "getStats", getStats_push};
00459 
00460 
00461 void Radio::txPkt()
00462 {
00463     uint8_t txlen = get_payload_length();
00464     radio.start_tx(txlen);
00465 }
00466 
00467 void Radio::Rx()
00468 {
00469     stat_t stat;
00470     uint8_t buf[3];
00471     unsigned rx_timeout = 0xffffff; // receive until instructed not to
00472     radio.to_big_endian24(rx_timeout, buf);
00473     stat.word = radio.xfer(OPCODE_SET_RX, 3, 0, buf);
00474     print_stat(stat);
00475 }
00476 
00477 void Radio::tx_carrier()
00478 {
00479     stat_t stat;
00480     stat.word = radio.xfer(OPCODE_SET_TXCW, 0, 0, NULL);
00481     print_stat(stat);
00482 }
00483 
00484 void Radio::tx_preamble()
00485 {
00486     stat_t stat;
00487     stat.word = radio.xfer(OPCODE_SET_TX_PREAMBLE, 0, 0, NULL);
00488     print_stat(stat);
00489 }
00490 
00491 void Radio::get_rssi()
00492 {
00493     stat_t stat;
00494     uint8_t buf;
00495     stat.word = radio.xfer(OPCODE_GET_RSSI_INST, 0, 0, NULL);
00496     stat.word = radio.xfer(0x0000, 0, 1, &buf); 
00497     log_printf("-%0.1f dBm\r\n", buf/2.0);   
00498 }
00499 
00500 void Radio::print_stat(stat_t stat)
00501 {
00502     char out[96];
00503     char str[24];
00504     out[0] = 0;
00505     if (stat.bits.rfu)
00506         strcat(out, "\e[41m");
00507     if ((stat.word & 0xff) != 0xff) {   // xfer returns 0xff for stat2 if stat2 didnt exist
00508         if (stat.bits.bootloader)
00509             strcat(out, "flash ");
00510         else
00511             strcat(out, "bootloader ");
00512         switch (stat.bits.chipMode) {
00513             case 0: strcat(out, "sleep"); break;
00514             case 1: strcat(out, "stby-rc"); break;
00515             case 2: strcat(out, "stby-xtal"); break;
00516             case 3: strcat(out, "\e[33mfs"); break;
00517             case 4: strcat(out, "\e[32mrx"); break;
00518             case 5: strcat(out, "\e[31mtx"); break;
00519             case 6: strcat(out, "\e[36mwifi/gnss"); break;
00520             default:
00521                 sprintf(str, "\e[31mchipmode:%u", stat.bits.chipMode);
00522                 strcat(out, str);
00523                 break;
00524         }
00525         strcat(out, "\e[0m ");
00526         if (stat.bits.resetStatus) {
00527             strcat(out, "reset:");
00528             switch (stat.bits.resetStatus) {
00529                 case 1: strcat(out, "analog"); break;
00530                 case 2: strcat(out, "pin"); break;
00531                 case 3: strcat(out, "system"); break;
00532                 case 4: strcat(out, "watchdog"); break;
00533                 case 5: strcat(out, "iocd"); break;
00534                 case 6: strcat(out, "rtc"); break;
00535                 default:
00536                     sprintf(str, "<%u>", stat.bits.resetStatus);
00537                     strcat(out, str);
00538                     break;
00539             }
00540             strcat(out, " ");
00541         }
00542     } // ..if stat2 exists
00543 
00544     sprintf(str, " %s ", radio.cmdStatus_toString(stat.bits.cmdStatus));
00545     strcat(out, str);
00546     if (stat.bits.intActive)
00547         strcat(out, "intActive ");
00548     if (stat.bits.rfu)
00549         strcat(out, "\e[0m");
00550 
00551     log_printf("%s\r\n", out);
00552 }
00553 
00554 
00555 void Radio::set_payload_length(uint8_t len)
00556 {
00557     uint8_t *buf_ptr = NULL;
00558     uint8_t buf_len = 0;
00559     uint8_t pktType = radio.getPacketType();
00560     if (pktType == PACKET_TYPE_LORA) {
00561         buf_len = 6;
00562         buf_ptr = lora_pp_buf;
00563         lora_pp_buf[3] = len;
00564     } else if (pktType == PACKET_TYPE_GFSK) {
00565         buf_len = 9;
00566         buf_ptr = gfsk_pp_buf;
00567         gfsk_pp_buf[6] = len;
00568     }
00569     radio.xfer(OPCODE_SET_PACKET_PARAM, buf_len, 0, buf_ptr);
00570 }
00571 
00572 bool Radio::PaSel_read()
00573 {
00574     txParamsB_t txpb;
00575     radio.memRegRead(REG_ADDR_TX_PARAMS_B, 1, &txpb.dword);
00576     pa_config_buf[0] = txpb.bits.PaSel;
00577     return txpb.bits.PaSel;
00578 }
00579 
00580 bool Radio::PaSel_push()
00581 {
00582     pa_config_buf[0] ^= 1;
00583     radio.xfer(OPCODE_SET_PA_CONFIG, 4, 0, pa_config_buf);
00584     return pa_config_buf[0] == 1;
00585 }
00586 
00587 const toggle_item_t Radio::PaSel_item = { _ITEM_TOGGLE, "PaSel:LP", "PaSel:HP", PaSel_read, PaSel_push};
00588 
00589 bool Radio::RegPASupply_read()
00590 {
00591     txParamsA_t tpa;
00592     radio.memRegRead(REG_ADDR_TX_PARAMS_A, 1, &tpa.dword);
00593     pa_config_buf[1] = tpa.bits.RegPASupply;
00594     return tpa.bits.RegPASupply;
00595 }
00596 
00597 bool Radio::RegPASupply_push(void)
00598 {
00599     pa_config_buf[1] ^= 1;
00600     radio.xfer(OPCODE_SET_PA_CONFIG, 4, 0, pa_config_buf);
00601     return pa_config_buf[1] == 1;
00602 }
00603 
00604 const toggle_item_t Radio::RegPASupply_item = { _ITEM_TOGGLE,
00605     "PASupply:intreg",
00606     "PASupply:vbat  ",
00607     RegPASupply_read,
00608     RegPASupply_push
00609 };
00610 
00611 void Radio::PaDutyCycle_print()
00612 {
00613     txParamsB_t tpb;
00614     radio.memRegRead(REG_ADDR_TX_PARAMS_B, 1, &tpb.dword);
00615     pa_config_buf[2] = tpb.bits.PaDutyCycle;
00616     printf("%u", tpb.bits.PaDutyCycle);
00617 }
00618 
00619 bool Radio::PaDutyCycle_write(const char *txt)
00620 {
00621     unsigned n;
00622     if (sscanf(txt, "%u", &n) == 1) {
00623         pa_config_buf[2] = n;
00624         radio.xfer(OPCODE_SET_PA_CONFIG, 4, 0, pa_config_buf);
00625     }
00626     return false;
00627 }
00628 
00629 const value_item_t Radio::PaDutyCycle_item = { _ITEM_VALUE, 3, PaDutyCycle_print, PaDutyCycle_write};
00630 
00631 void Radio::PaHPSel_print()
00632 {
00633     txParamsB_t tpb;
00634     radio.memRegRead(REG_ADDR_TX_PARAMS_B, 1, &tpb.dword);
00635     pa_config_buf[3] = tpb.bits.PaHPSel;
00636     printf("%u", tpb.bits.PaHPSel);
00637 }
00638 
00639 bool Radio::PaHPSel_write(const char *txt)
00640 {
00641     unsigned n;
00642     if (sscanf(txt, "%u", &n) == 1) {
00643         pa_config_buf[3] = n;
00644         radio.xfer(OPCODE_SET_PA_CONFIG, 4, 0, pa_config_buf);
00645     }
00646     return false;
00647 }
00648 
00649 const value_item_t Radio::PaHPSel_item = { _ITEM_VALUE, 3, PaHPSel_print, PaHPSel_write};
00650 
00651 
00652 void Radio::wifiScan_push()
00653 {
00654     radio.xfer(OPCODE_WIFI_SCAN, 9, 0, wifiScan_buf);
00655     log_printf("wifiScan...\r\n");
00656 }
00657 
00658 const char* const wifitype_strs[] = 
00659 {
00660     "802.11b", // 1
00661     "802.11g", // 2
00662     "802.11n", // 3
00663     "  all  ", // 4
00664     NULL
00665 };
00666 
00667 unsigned wifitype_read(bool for_writing)
00668 {
00669     return wifiScan_buf[0] - 1;
00670 }
00671 
00672 menuMode_e wifitype_write(unsigned sidx)
00673 {
00674     wifiScan_buf[0] = sidx + 1;
00675     return MENUMODE_REDRAW;
00676 }
00677 
00678 const dropdown_item_t wifiType_item = { _ITEM_DROPDOWN, wifitype_strs, wifitype_strs, wifitype_read, wifitype_write };
00679 
00680 bool wifiAcqMode_read()
00681 {
00682     return wifiScan_buf[3] == 2;
00683 }
00684 
00685 bool wifiAcqMode_push()
00686 {
00687     wifiScan_buf[3] == 2 ?  wifiScan_buf[3] = 1 : wifiScan_buf[3] = 2;
00688     return wifiScan_buf[3] == 2;
00689 }
00690 
00691 const toggle_item_t wifiAcqMode_item = { _ITEM_TOGGLE,
00692     "beacon-only  ",
00693     "beacon+Packet",
00694     wifiAcqMode_read,
00695     wifiAcqMode_push
00696 };
00697 
00698 void wifiNbMaxRes_print()
00699 {
00700     printf("%u", wifiScan_buf[4]);
00701 }
00702 
00703 bool wifiNbMaxRes_write(const char *txt)
00704 {
00705     unsigned n;
00706     sscanf(txt, "%u", &n);
00707     wifiScan_buf[4] = n;
00708     return false;
00709 }
00710 
00711 const value_item_t wifiNbMaxRes_item = { _ITEM_VALUE, 3, wifiNbMaxRes_print, wifiNbMaxRes_write};
00712 
00713 void wifiNbScanPerChan_print()
00714 {
00715     printf("%u", wifiScan_buf[5]);
00716 }
00717 
00718 bool wifiNbScanPerChan_write(const char *txt)
00719 {
00720     unsigned n;
00721     sscanf(txt, "%u", &n);
00722     wifiScan_buf[5] = n;
00723     return false;
00724 }
00725 
00726 const value_item_t wifiNbScanPerChan_item = { _ITEM_VALUE, 3, wifiNbScanPerChan_print, wifiNbScanPerChan_write};
00727 
00728 
00729 
00730 const button_item_t Radio::wifiScan_item = { _ITEM_BUTTON, "wifiScan", wifiScan_push };
00731 
00732 bool wifi_ch14_read() { return (wifiScan_buf[1] & 0x20) == 0x20; }
00733 bool wifi_ch14_push() { wifiScan_buf[1] ^= 0x20; return wifi_ch14_read(); }
00734 const toggle_item_t wifi_ch14_item = { _ITEM_TOGGLE, "ch14", NULL, wifi_ch14_read, wifi_ch14_push};
00735 
00736 bool wifi_ch13_read() { return (wifiScan_buf[1] & 0x10) == 0x10; }
00737 bool wifi_ch13_push() { wifiScan_buf[1] ^= 0x10; return wifi_ch13_read(); }
00738 const toggle_item_t wifi_ch13_item = { _ITEM_TOGGLE, "ch13", NULL, wifi_ch13_read, wifi_ch13_push};
00739 
00740 bool wifi_ch12_read() { return (wifiScan_buf[1] & 0x08) == 0x08; }
00741 bool wifi_ch12_push() { wifiScan_buf[1] ^= 0x08; return wifi_ch12_read(); }
00742 const toggle_item_t wifi_ch12_item = { _ITEM_TOGGLE, "ch12", NULL, wifi_ch12_read, wifi_ch12_push};
00743 
00744 bool wifi_ch11_read() { return (wifiScan_buf[1] & 0x04) == 0x04; }
00745 bool wifi_ch11_push() { wifiScan_buf[1] ^= 0x08; return wifi_ch11_read(); }
00746 const toggle_item_t wifi_ch11_item = { _ITEM_TOGGLE, "ch11", NULL, wifi_ch11_read, wifi_ch11_push};
00747 
00748 bool wifi_ch10_read() { return (wifiScan_buf[1] & 0x02) == 0x02; }
00749 bool wifi_ch10_push() { wifiScan_buf[1] ^= 0x02; return wifi_ch10_read(); }
00750 const toggle_item_t wifi_ch10_item = { _ITEM_TOGGLE, "ch10", NULL, wifi_ch10_read, wifi_ch10_push};
00751 
00752 bool wifi_ch9_read() { return (wifiScan_buf[1] & 0x01) == 0x01; }
00753 bool wifi_ch9_push() { wifiScan_buf[1] ^= 0x01; return wifi_ch9_read(); }
00754 const toggle_item_t wifi_ch9_item = { _ITEM_TOGGLE, "ch9", NULL, wifi_ch9_read, wifi_ch9_push};
00755 
00756 bool wifi_ch8_read() { return (wifiScan_buf[2] & 0x80) == 0x80; }
00757 bool wifi_ch8_push() { wifiScan_buf[2] ^= 0x80; return wifi_ch8_read(); }
00758 const toggle_item_t wifi_ch8_item = { _ITEM_TOGGLE, "ch8", NULL, wifi_ch8_read, wifi_ch8_push};
00759 
00760 bool wifi_ch7_read() { return (wifiScan_buf[2] & 0x40) == 0x40; }
00761 bool wifi_ch7_push() { wifiScan_buf[2] ^= 0x40; return wifi_ch7_read(); }
00762 const toggle_item_t wifi_ch7_item = { _ITEM_TOGGLE, "ch7", NULL, wifi_ch7_read, wifi_ch7_push};
00763 
00764 bool wifi_ch6_read() { return (wifiScan_buf[2] & 0x20) == 0x20; }
00765 bool wifi_ch6_push() { wifiScan_buf[2] ^= 0x20; return wifi_ch6_read(); }
00766 const toggle_item_t wifi_ch6_item = { _ITEM_TOGGLE, "ch6", NULL, wifi_ch6_read, wifi_ch6_push};
00767 
00768 bool wifi_ch5_read() { return (wifiScan_buf[2] & 0x10) == 0x10; }
00769 bool wifi_ch5_push() { wifiScan_buf[2] ^= 0x10; return wifi_ch5_read(); }
00770 const toggle_item_t wifi_ch5_item = { _ITEM_TOGGLE, "ch5", NULL, wifi_ch5_read, wifi_ch5_push};
00771 
00772 bool wifi_ch4_read() { return (wifiScan_buf[2] & 0x08) == 0x08; }
00773 bool wifi_ch4_push() { wifiScan_buf[2] ^= 0x08; return wifi_ch4_read(); }
00774 const toggle_item_t wifi_ch4_item = { _ITEM_TOGGLE, "ch4", NULL, wifi_ch4_read, wifi_ch4_push};
00775 
00776 bool wifi_ch3_read() { return (wifiScan_buf[2] & 0x04) == 0x04; }
00777 bool wifi_ch3_push() { wifiScan_buf[2] ^= 0x04; return wifi_ch3_read(); }
00778 const toggle_item_t wifi_ch3_item = { _ITEM_TOGGLE, "ch3", NULL, wifi_ch3_read, wifi_ch3_push};
00779 
00780 bool wifi_ch2_read() { return (wifiScan_buf[2] & 0x02) == 0x02; }
00781 bool wifi_ch2_push() { wifiScan_buf[2] ^= 0x02; return wifi_ch2_read(); }
00782 const toggle_item_t wifi_ch2_item = { _ITEM_TOGGLE, "ch2", NULL, wifi_ch2_read, wifi_ch2_push};
00783 
00784 bool wifi_ch1_read() { return (wifiScan_buf[2] & 0x01) == 0x01; }
00785 bool wifi_ch1_push() { wifiScan_buf[2] ^= 0x01; return wifi_ch1_read(); }
00786 const toggle_item_t wifi_ch1_item = { _ITEM_TOGGLE, "ch1", NULL, wifi_ch1_read, wifi_ch1_push};
00787 
00788 void wifiTimeout_print(void)
00789 {
00790     unsigned t;
00791     t = wifiScan_buf[6];
00792     t <<= 8;
00793     t |= wifiScan_buf[7];
00794     printf("%u", t);
00795 }
00796 
00797 bool wifiTimeout_write(const char *txt)
00798 {
00799     unsigned t;
00800     sscanf(txt, "%u", &t);
00801     wifiScan_buf[7] = t;
00802     t >>= 8;
00803     wifiScan_buf[6] = t;
00804     return false;
00805 }
00806 
00807 const value_item_t wifiTimeout_item = { _ITEM_VALUE, 6, wifiTimeout_print, wifiTimeout_write};
00808 
00809 bool AbortOnTimeout_read()
00810 {
00811     return wifiScan_buf[8] == 1;
00812 }
00813 
00814 bool AbortOnTimeout_push()
00815 {
00816     wifiScan_buf[8] ^= 1;
00817     return wifiScan_buf[8] == 1;
00818 }
00819 
00820 const toggle_item_t wifiAbort_item = { _ITEM_TOGGLE, "AbortOnTimeout", NULL, AbortOnTimeout_read, AbortOnTimeout_push};
00821 
00822 bool wifiResultFormat_read()
00823 {
00824     // false=full, true=basic
00825     return wifiResultFormatBasic;
00826 }
00827 
00828 bool wifiResultFormat_push()
00829 {
00830     // false=full, true=basic
00831     wifiResultFormatBasic ^= true;
00832     return wifiResultFormatBasic;
00833 }
00834 
00835 const toggle_item_t wifiResultFormat_item = { _ITEM_TOGGLE,
00836     "full ",
00837     "basic",
00838     wifiResultFormat_read,
00839     wifiResultFormat_push
00840 };
00841 
00842 void Radio::gnssAutonomous_push()
00843 {
00844     gnssAutonomous_buf[4] = 0;  // EffortMode
00845     radio.xfer(OPCODE_GNSS_AUTONOMOUS, 7, 0, gnssAutonomous_buf);
00846     log_printf("gnssAutonomous...\r\n");
00847 }
00848 
00849 const button_item_t Radio::gnssAutonomous_item = { _ITEM_BUTTON, "gnssAutonomous", gnssAutonomous_push };
00850 
00851 void gnssAutonomous_time_print()
00852 {
00853     unsigned t = Radio::radio.from_big_endian32(gnssAutonomous_buf);
00854     printf("%u", t);
00855 }
00856 
00857 bool gnssAutonomous_time_write(const char *txt)
00858 {
00859     unsigned t;
00860     if (sscanf(txt, "%u", &t) == 1) {
00861         Radio::radio.to_big_endian32(t, gnssAutonomous_buf);
00862     }
00863     return false;
00864 }
00865 
00866 
00867 bool gnssAutoResultTimeStamp_read()
00868 {
00869     return (gnssAutonomous_buf[5] & 0x01) == 0x01;
00870 }
00871 bool gnssAutoResultTimeStamp_push()
00872 {
00873     gnssAutonomous_buf[5] ^= 0x01;
00874     return (gnssAutonomous_buf[5] & 0x01) == 0x01;
00875 }
00876 const toggle_item_t gnssAutoResultTimeStamp_item = { _ITEM_TOGGLE, "timestamp", NULL, gnssAutoResultTimeStamp_read, gnssAutoResultTimeStamp_push};
00877 
00878 bool gnssAutoResultDoppler_read()
00879 {
00880     return (gnssAutonomous_buf[5] & 0x02) == 0x02;
00881 }
00882 bool gnssAutoResultDoppler_push()
00883 {
00884     gnssAutonomous_buf[5] ^= 0x02;
00885     return (gnssAutonomous_buf[5] & 0x02) == 0x02;
00886 }
00887 const toggle_item_t gnssAutoResultDoppler_item = { _ITEM_TOGGLE, "doppler", NULL, gnssAutoResultDoppler_read, gnssAutoResultDoppler_push};
00888 
00889 bool gnssAutoResultBitChange_read()
00890 {
00891     return (gnssAutonomous_buf[5] & 0x04) == 0x04;
00892 }
00893 bool gnssAutoResultBitChange_push()
00894 {
00895     gnssAutonomous_buf[5] ^= 0x04;
00896     return (gnssAutonomous_buf[5] & 0x04) == 0x04;
00897 }
00898 const toggle_item_t gnssAutoResultBitChange_item = { _ITEM_TOGGLE, "bit change", NULL, gnssAutoResultBitChange_read, gnssAutoResultBitChange_push};
00899 
00900 void gnssAutoNbSvMax_print()
00901 {
00902     printf("%u", gnssAutonomous_buf[6]);
00903 }
00904 
00905 bool gnssAutoNbSvMax_write(const char *txt)
00906 {
00907     unsigned n;
00908     sscanf(txt, "%u", &n);
00909     gnssAutonomous_buf[6] = n;
00910     return false;
00911 }
00912 
00913 const value_item_t gnssAutoNbSvMax_item = { _ITEM_VALUE, 3, gnssAutoNbSvMax_print, gnssAutoNbSvMax_write};
00914 
00915 const value_item_t gnssAutonomous_time_item = { _ITEM_VALUE, 9, gnssAutonomous_time_print, gnssAutonomous_time_write};
00916 
00917 void Radio::gnssAssisted_push()
00918 {
00919     gnssAssisted_buf[5] = 3; // ResultMask
00920     radio.xfer(OPCODE_GNSS_ASSISTED, 7, 0, gnssAssisted_buf);
00921     log_printf("gnssAssisted...\r\n");
00922 }
00923 
00924 const button_item_t Radio::gnssAssisted_item = { _ITEM_BUTTON, "gnssAssisted", gnssAssisted_push};
00925 
00926 void gnssAssisted_time_print()
00927 {
00928     unsigned t = Radio::radio.from_big_endian32(gnssAssisted_buf);
00929     printf("%u", t);
00930 }
00931 
00932 bool gnssAssisted_time_write(const char *txt)
00933 {
00934     unsigned t;
00935     if (sscanf(txt, "%u", &t) == 1) {
00936         Radio::radio.to_big_endian32(t, gnssAssisted_buf);
00937     }
00938     return false;
00939 }
00940 const value_item_t gnssAssisted_time_item = { _ITEM_VALUE, 9, gnssAssisted_time_print, gnssAssisted_time_write};
00941 
00942 bool gnssAssisted_effort_read()
00943 {
00944     return gnssAssisted_buf[4] == 0x01;
00945 }
00946 
00947 bool gnssAssisted_effort_push()
00948 {
00949     gnssAssisted_buf[4] ^= 0x01;
00950     return gnssAssisted_buf[4] == 0x01;
00951 }
00952 
00953 const toggle_item_t gnssAssisted_effort_item = { _ITEM_TOGGLE,
00954     "lowPower",
00955     "best    ",
00956     gnssAssisted_effort_read,
00957     gnssAssisted_effort_push
00958 };
00959 
00960 void gnssAssisted_nbsvmax_print()
00961 {
00962     printf("%u", gnssAssisted_buf[6]);
00963 }
00964 
00965 bool gnssAssisted_nbsvmax_write(const char *txt)
00966 {
00967     unsigned n;
00968     sscanf(txt, "%u", &n);
00969     gnssAssisted_buf[6] = n;
00970     return false;
00971 }
00972 
00973 const value_item_t gnssAssisted_nbsvmax_item = { _ITEM_VALUE, 3, gnssAssisted_nbsvmax_print, gnssAssisted_nbsvmax_write};
00974 
00975 bool gnss_const_gps_enable_read()
00976 {
00977     gnssConstellation_t gc;
00978     Radio::radio.memRegRead(REG_ADDR_GNSS_CONST, 1, &gc.dword);
00979     return gc.bits.gps;
00980 }
00981 
00982 bool gnss_const_gps_enable_push()
00983 {
00984     uint8_t ConstellationBitMask = 0;
00985     gnssConstellation_t gc;
00986     Radio::radio.memRegRead(REG_ADDR_GNSS_CONST, 1, &gc.dword);
00987     if (gc.bits.gps)
00988         ConstellationBitMask &= ~1;
00989     else
00990         ConstellationBitMask |= 1;
00991     if (gc.bits.beidou)
00992         ConstellationBitMask |= 2;
00993     Radio::radio.xfer(OPCODE_GNSS_SET_CONSTELLATION, 1, 0, &ConstellationBitMask);
00994     return ConstellationBitMask & 1;
00995 }
00996 
00997 const toggle_item_t gnss_const_gps_enable_item = { _ITEM_TOGGLE, "GPS", NULL, gnss_const_gps_enable_read, gnss_const_gps_enable_push};
00998 
00999 bool gnss_const_beidou_enable_read()
01000 {
01001     gnssConstellation_t gc;
01002     Radio::radio.memRegRead(REG_ADDR_GNSS_CONST, 1, &gc.dword);
01003     return gc.bits.beidou;
01004 }
01005 
01006 bool gnss_const_beidou_enable_push()
01007 {
01008     uint8_t ConstellationBitMask = 0;
01009     gnssConstellation_t gc;
01010     Radio::radio.memRegRead(REG_ADDR_GNSS_CONST, 1, &gc.dword);
01011     if (gc.bits.beidou)
01012         ConstellationBitMask &= ~2;
01013     else
01014         ConstellationBitMask |= 2;
01015     if (gc.bits.gps)
01016         ConstellationBitMask |= 1;
01017     Radio::radio.xfer(OPCODE_GNSS_SET_CONSTELLATION, 1, 0, &ConstellationBitMask);
01018     return ConstellationBitMask & 1;
01019 }
01020 
01021 const toggle_item_t gnss_const_beidou_enable_item = { _ITEM_TOGGLE, "BEIDOU", NULL, gnss_const_beidou_enable_read, gnss_const_beidou_enable_push};
01022 
01023 bool gnssmode_read()
01024 {
01025     gnssMode_t gm;
01026     Radio::radio.memRegRead(REG_ADDR_GNSS_MODE, 1, &gm.dword);
01027     return gm.bits.gnss_scan_single;
01028 }
01029 
01030 bool gnssmode_push()
01031 {
01032     uint8_t buf = gnssmode_read();  // GnssSetMode takes 1 for dual-scan
01033     Radio::radio.xfer(OPCODE_GNSS_SET_MODE, 1, 0, &buf);
01034     return buf == 0;
01035 }
01036 
01037 const toggle_item_t gnss_mode_item = { _ITEM_TOGGLE,
01038     "dual  ",
01039     "single",
01040     gnssmode_read,
01041     gnssmode_push
01042 };
01043 
01044 const menu_t Radio::common_menu[] = {
01045     { {FIRST_CHIP_MENU_ROW,  1},          NULL, &PaSel_item, FLAG_MSGTYPE_ALL, &tx_dbm_item},
01046     { {FIRST_CHIP_MENU_ROW, 10},          NULL, &RegPASupply_item, FLAG_MSGTYPE_ALL},
01047     { {FIRST_CHIP_MENU_ROW, 30}, "PaDutyCycle:", &PaDutyCycle_item, FLAG_MSGTYPE_ALL},
01048     { {FIRST_CHIP_MENU_ROW, 47},     "PaHPSel:", &PaHPSel_item, FLAG_MSGTYPE_ALL},
01049 
01050     { {FIRST_CHIP_MENU_ROW+1,  1}, "regulator:", &regulator_item, FLAG_MSGTYPE_ALL},
01051     { {FIRST_CHIP_MENU_ROW+1,  18}, "tcxoVolts:", &tcxo_volts_item, FLAG_MSGTYPE_ALL},
01052     { {FIRST_CHIP_MENU_ROW+1,  32}, "tcxoDelay(ms):", &tcxo_delay_item, FLAG_MSGTYPE_ALL},
01053     { {FIRST_CHIP_MENU_ROW+1,  52}, "re-cal(hex):", &recalibrate_item, FLAG_MSGTYPE_ALL},
01054 
01055    //012345678901234567890
01056 
01057     { {FIRST_CHIP_MENU_ROW+2,  1}, "txTimeout(sec):", &txTimeout_item, FLAG_MSGTYPE_ALL},
01058     { {FIRST_CHIP_MENU_ROW+2, 24},              NULL, &rxBufferStatus_item, FLAG_MSGTYPE_ALL},
01059     { {FIRST_CHIP_MENU_ROW+2, 35},              NULL, &getStats_item, FLAG_MSGTYPE_ALL},
01060 
01061     { {FIRST_CHIP_MENU_ROW+10,  1},          NULL, &wifiScan_item, FLAG_MSGTYPE_ALL},
01062     { {FIRST_CHIP_MENU_ROW+10, 10},          NULL, &wifiType_item, FLAG_MSGTYPE_ALL},
01063     { {FIRST_CHIP_MENU_ROW+10, 19},          NULL, &wifiAcqMode_item, FLAG_MSGTYPE_ALL},
01064     { {FIRST_CHIP_MENU_ROW+10, 35},   "NbMaxRes:", &wifiNbMaxRes_item, FLAG_MSGTYPE_ALL},
01065     { {FIRST_CHIP_MENU_ROW+10, 48}, "NbScanPerChan:", &wifiNbScanPerChan_item, FLAG_MSGTYPE_ALL},
01066 
01067     { {FIRST_CHIP_MENU_ROW+11,  1}, "timeout(ms):", &wifiTimeout_item, FLAG_MSGTYPE_ALL},
01068     { {FIRST_CHIP_MENU_ROW+11, 20},           NULL, &wifiAbort_item, FLAG_MSGTYPE_ALL},
01069     { {FIRST_CHIP_MENU_ROW+11, 45}, "resultFormat:", &wifiResultFormat_item, FLAG_MSGTYPE_ALL},
01070 
01071 
01072     { {FIRST_CHIP_MENU_ROW+12,  1},        NULL, &wifi_ch14_item, FLAG_MSGTYPE_ALL},
01073     { {FIRST_CHIP_MENU_ROW+12,  6},        NULL, &wifi_ch13_item, FLAG_MSGTYPE_ALL},
01074     { {FIRST_CHIP_MENU_ROW+12, 11},        NULL, &wifi_ch12_item, FLAG_MSGTYPE_ALL},
01075     { {FIRST_CHIP_MENU_ROW+12, 16},        NULL, &wifi_ch11_item, FLAG_MSGTYPE_ALL},
01076     { {FIRST_CHIP_MENU_ROW+12, 21},        NULL, &wifi_ch10_item, FLAG_MSGTYPE_ALL},
01077     { {FIRST_CHIP_MENU_ROW+12, 26},        NULL, &wifi_ch9_item, FLAG_MSGTYPE_ALL},
01078     { {FIRST_CHIP_MENU_ROW+12, 31},        NULL, &wifi_ch8_item, FLAG_MSGTYPE_ALL},
01079     { {FIRST_CHIP_MENU_ROW+12, 36},        NULL, &wifi_ch7_item, FLAG_MSGTYPE_ALL},
01080     { {FIRST_CHIP_MENU_ROW+12, 41},        NULL, &wifi_ch6_item, FLAG_MSGTYPE_ALL},
01081     { {FIRST_CHIP_MENU_ROW+12, 46},        NULL, &wifi_ch5_item, FLAG_MSGTYPE_ALL},
01082     { {FIRST_CHIP_MENU_ROW+12, 51},        NULL, &wifi_ch4_item, FLAG_MSGTYPE_ALL},
01083     { {FIRST_CHIP_MENU_ROW+12, 56},        NULL, &wifi_ch3_item, FLAG_MSGTYPE_ALL},
01084     { {FIRST_CHIP_MENU_ROW+12, 61},        NULL, &wifi_ch2_item, FLAG_MSGTYPE_ALL},
01085     { {FIRST_CHIP_MENU_ROW+12, 66},        NULL, &wifi_ch1_item, FLAG_MSGTYPE_ALL},
01086 
01087     { {FIRST_CHIP_MENU_ROW+13,  1},        NULL, &gnss_const_gps_enable_item, FLAG_MSGTYPE_ALL},
01088     { {FIRST_CHIP_MENU_ROW+13,  5},        NULL, &gnss_const_beidou_enable_item, FLAG_MSGTYPE_ALL},
01089     { {FIRST_CHIP_MENU_ROW+13, 12},     "scanning:", &gnss_mode_item, FLAG_MSGTYPE_ALL},
01090 
01091     { {FIRST_CHIP_MENU_ROW+14,  1},          NULL, &gnssAutonomous_item, FLAG_MSGTYPE_ALL},
01092     { {FIRST_CHIP_MENU_ROW+14, 16},       "time:", &gnssAutonomous_time_item, FLAG_MSGTYPE_ALL},
01093     { {FIRST_CHIP_MENU_ROW+14, 31},          NULL, &gnssAutoResultTimeStamp_item, FLAG_MSGTYPE_ALL},
01094     { {FIRST_CHIP_MENU_ROW+14, 41},          NULL, &gnssAutoResultDoppler_item, FLAG_MSGTYPE_ALL},
01095     { {FIRST_CHIP_MENU_ROW+14, 51},          NULL, &gnssAutoResultBitChange_item, FLAG_MSGTYPE_ALL},
01096     { {FIRST_CHIP_MENU_ROW+14, 63},    "NbSvMax:", &gnssAutoNbSvMax_item, FLAG_MSGTYPE_ALL},
01097 
01098     { {FIRST_CHIP_MENU_ROW+15,  1},          NULL, &gnssAssisted_item, FLAG_MSGTYPE_ALL},
01099     { {FIRST_CHIP_MENU_ROW+15, 16},       "time:", &gnssAssisted_time_item, FLAG_MSGTYPE_ALL},
01100     { {FIRST_CHIP_MENU_ROW+15, 30},     "effort:", &gnssAssisted_effort_item, FLAG_MSGTYPE_ALL},
01101     { {FIRST_CHIP_MENU_ROW+15, 50},   "NbSvMax::", &gnssAssisted_nbsvmax_item, FLAG_MSGTYPE_ALL},
01102 
01103    //0123456789012345
01104     { {0, 0}, NULL, NULL }
01105 };
01106 
01107 void Radio::gfsk_bitrate_print()
01108 {
01109     uint32_t u32;
01110     unsigned hz;
01111     radio.memRegRead(REG_ADDR_GFSK_BITRATE, 1, &u32);
01112     hz = GFSK_BITRATE_NUMERATOR / u32;
01113     printf("%u", hz);
01114     radio.to_big_endian32(hz, gfsk_mp_buf);
01115 }
01116 
01117 bool Radio::gfsk_bitrate_write(const char* txt)
01118 {
01119     unsigned bps;
01120 
01121     if (sscanf(txt, "%u", &bps) == 1) {
01122         radio.to_big_endian32(bps, gfsk_mp_buf);
01123         radio.xfer(OPCODE_SET_MODULATION, 10, 0, gfsk_mp_buf);
01124     }
01125     return false;
01126 }
01127 
01128 const value_item_t Radio::gfsk_bitrate_item = { _ITEM_VALUE, 8, gfsk_bitrate_print, gfsk_bitrate_write};
01129 
01130 static const char* const gfsk_bts[] = {
01131     "off", // 0
01132     "0.3", // 1
01133     "0.5", // 2
01134     "0.7", // 3
01135     "1.0", // 4
01136     NULL
01137 };
01138 
01139 unsigned Radio::gfsk_bt_read(bool forWriting)
01140 {
01141     gfskConfig0_t cfg0;
01142     radio.memRegRead(REG_ADDR_GFSK_CFG0, 1, &cfg0.dword);
01143     if (cfg0.bits.shaping_en) {
01144         switch (cfg0.bits.bt) {
01145             case 0: /* off */ gfsk_mp_buf[4] = GFSK_BT_OFF; break;
01146             case 1: /* 0.3 */ gfsk_mp_buf[4] = GFSK_BT_0_3; break;
01147             case 2: /* 0.5 */ gfsk_mp_buf[4] = GFSK_BT_0_5; break;
01148             case 3: /* 0.7 */ gfsk_mp_buf[4] = GFSK_BT_0_7; break;
01149             case 4: /* 1.0 */ gfsk_mp_buf[4] = GFSK_BT_1_0; break;
01150         }
01151         return cfg0.bits.bt + 1;
01152     } else
01153         return 0;
01154 }
01155 
01156 menuMode_e Radio::gfsk_bt_write(unsigned sidx)
01157 {
01158     switch (sidx) {
01159         case 0: gfsk_mp_buf[4] = GFSK_BT_OFF; break;
01160         case 1: gfsk_mp_buf[4] = GFSK_BT_0_3; break;
01161         case 2: gfsk_mp_buf[4] = GFSK_BT_0_5; break;
01162         case 3: gfsk_mp_buf[4] = GFSK_BT_0_7; break;
01163         case 4: gfsk_mp_buf[4] = GFSK_BT_1_0; break;
01164     }
01165     radio.xfer(OPCODE_SET_MODULATION, 10, 0, gfsk_mp_buf);
01166     return MENUMODE_REDRAW;
01167 }
01168 
01169 const dropdown_item_t Radio::gfsk_bt_item = { _ITEM_DROPDOWN, gfsk_bts, gfsk_bts, gfsk_bt_read, gfsk_bt_write};
01170 
01171 void Radio::gfsk_rxbw_print()
01172 {
01173     unsigned n;
01174     uint8_t bwf;
01175     gfskBW_t bw_reg;
01176     radio.memRegRead(REG_ADDR_GFSK_BWF, 1, &bw_reg.dword);
01177     bwf = bw_reg.bits.bwf_hi;
01178     bwf <<= 3;
01179     bwf |= bw_reg.bits.bwf_lo;
01180     gfsk_mp_buf[5] = bwf;
01181 
01182     for (n = 0; n < NB_RXBW; n++) {
01183         if (rxbws[n].bwf == bwf) {
01184             printf("%u", rxbws[n].hz);
01185             break;
01186         }
01187     }
01188 }
01189 
01190 rxbw_t Radio::rxbws[] = {
01191     /*  0 */ {   4800, GFSK_RX_BW_4800 },
01192     /*  1 */ {   5800, GFSK_RX_BW_5800 },
01193     /*  2 */ {   7300, GFSK_RX_BW_7300 },
01194     /*  3 */ {   9700, GFSK_RX_BW_9700 },
01195     /*  4 */ {  11700, GFSK_RX_BW_11700 },
01196     /*  5 */ {  14600, GFSK_RX_BW_14600 },
01197     /*  6 */ {  19500, GFSK_RX_BW_19500 },
01198     /*  7 */ {  23400, GFSK_RX_BW_23400 },
01199     /*  8 */ {  29300, GFSK_RX_BW_29300 },
01200     /*  9 */ {  39000, GFSK_RX_BW_39000 },
01201     /* 10 */ {  46900, GFSK_RX_BW_46900 },
01202     /* 11 */ {  58600, GFSK_RX_BW_58600 },
01203     /* 12 */ {  78200, GFSK_RX_BW_78200 },
01204     /* 13 */ {  93800, GFSK_RX_BW_93800 },
01205     /* 14 */ { 117300, GFSK_RX_BW_117300 },
01206     /* 15 */ { 156200, GFSK_RX_BW_156200 },
01207     /* 16 */ { 187200, GFSK_RX_BW_187200 },
01208     /* 17 */ { 234300, GFSK_RX_BW_234300 },
01209     /* 18 */ { 312000, GFSK_RX_BW_312000 },
01210     /* 19 */ { 373600, GFSK_RX_BW_373600 },
01211     /* 20 */ { 467000, GFSK_RX_BW_467000 }
01212 };
01213 
01214 bool Radio::gfsk_rxbw_write(const char* txt)
01215 {
01216     unsigned n, rxbw;
01217     if (sscanf(txt, "%u", &rxbw) == 1) {
01218         for (n = 1; n < NB_RXBW; n++) {
01219             log_printf("%u) %u > %u\r\n", n, rxbw, rxbws[n].hz);
01220             if (rxbw >= rxbws[n-1].hz && rxbw < rxbws[n].hz) {
01221                 gfsk_mp_buf[5] = rxbws[n-1].bwf;
01222                 log_printf("RXBWset %u<-%u %02x\r\n", rxbws[n-1].hz, rxbw, gfsk_mp_buf[5]);
01223                 break;
01224             }
01225         }
01226         radio.xfer(OPCODE_SET_MODULATION, 10, 0, gfsk_mp_buf);
01227     }
01228     return false;
01229 }
01230 
01231 const value_item_t Radio::gfsk_rxbw_item = { _ITEM_VALUE, 8, gfsk_rxbw_print, gfsk_rxbw_write};
01232 
01233 void Radio::gfsk_fdev_print()
01234 {
01235     unsigned hz;
01236     uint32_t u32;
01237     radio.memRegRead(REG_ADDR_GFSK_FDEV, 1, &u32);
01238     hz = my_round(u32 * FREQ_STEP);
01239     printf("%u", hz);
01240     radio.to_big_endian32(hz, gfsk_mp_buf+6);
01241 }
01242 
01243 bool Radio::gfsk_fdev_write(const char* txt)
01244 {
01245     unsigned hz;
01246     if (sscanf(txt, "%u", &hz) == 1) {
01247         radio.to_big_endian32(hz, gfsk_mp_buf+6);
01248         radio.xfer(OPCODE_SET_MODULATION, 10, 0, gfsk_mp_buf);
01249     }
01250     return false;
01251 }
01252 
01253 const value_item_t Radio::gfsk_fdev_item = { _ITEM_VALUE, 8, gfsk_fdev_print, gfsk_fdev_write};
01254 
01255 void Radio::gfsk_pblLen_print()
01256 {
01257     unsigned n;
01258     gfskConfig1_t cfg1;
01259     radio.memRegRead(REG_ADDR_GFSK_CFG1, 1, &cfg1.dword);
01260     printf("%u", cfg1.bits.preamble_length);
01261     n = cfg1.bits.preamble_length;
01262     gfsk_pp_buf[1] = n;
01263     n >>= 8;
01264     gfsk_pp_buf[0] = n;
01265 }
01266 
01267 bool Radio::gfsk_pblLen_write(const char* txt)
01268 {
01269     unsigned n;
01270     if (sscanf(txt, "%u", &n) == 1) {
01271         radio.to_big_endian16(n, gfsk_pp_buf);
01272         radio.xfer(OPCODE_SET_PACKET_PARAM, 9, 0, gfsk_pp_buf);
01273     }
01274     return false;
01275 }
01276 
01277 const value_item_t Radio::gfsk_pblLen_item = { _ITEM_VALUE, 5, gfsk_pblLen_print, gfsk_pblLen_write};
01278 
01279 static const char* const fsk_detlens[] = {
01280     " off  ", // GFSK_PBLDET_LENGTH_OFF  0x00
01281     " 8bits", // GFSK_PBLDET_LENGTH_8    0x04
01282     "16bits", // GFSK_PBLDET_LENGTH_16   0x05
01283     "24bits", // GFSK_PBLDET_LENGTH_24   0x06
01284     "32bits", // GFSK_PBLDET_LENGTH_32   0x07
01285     NULL
01286 };
01287 
01288 unsigned Radio::gfsk_pblDetLen_read(bool forWriting)
01289 {
01290     gfskConfig1_t cfg1;
01291     radio.memRegRead(REG_ADDR_GFSK_CFG1, 1, &cfg1.dword);
01292     if (cfg1.bits.preamble_det_enable) {
01293         gfsk_pp_buf[2] = cfg1.bits.preamble_det_len + 4;
01294         return cfg1.bits.preamble_det_len + 1;
01295     } else {
01296         gfsk_pp_buf[2] = 0;
01297         return 0;
01298     }
01299 }
01300 
01301 menuMode_e Radio::gfsk_pblDetLen_write(unsigned sidx)
01302 {
01303     if (sidx == 0)
01304         gfsk_pp_buf[2] = 0;
01305     else
01306         gfsk_pp_buf[2] = sidx + 4;
01307 
01308     radio.xfer(OPCODE_SET_PACKET_PARAM, 9, 0, gfsk_pp_buf);
01309     return MENUMODE_REDRAW;
01310 }
01311 
01312 const dropdown_item_t Radio::gfsk_pblDetLen_item = { _ITEM_DROPDOWN, fsk_detlens, fsk_detlens, gfsk_pblDetLen_read, gfsk_pblDetLen_write};
01313 
01314 void Radio::gfsk_syncWord_print(void)
01315 {
01316     uint32_t dword[2];
01317     radio.memRegRead(REG_ADDR_GFSK_SYNC_LO, 2, dword);
01318     printf("%08lx", dword[1]);
01319     printf("%08lx", dword[0]);
01320 }
01321 
01322 bool Radio::gfsk_syncWord_write(const char* txt)
01323 {
01324     uint8_t buf[8];
01325     const char* ptr;
01326     const char* endPtr;
01327     unsigned o, n = 0;
01328 
01329     endPtr = txt + strlen(txt);
01330     for (ptr = txt; sscanf(ptr, "%02x", &o) == 1; ) {
01331         buf[n++] = o;
01332         ptr += 2;
01333         if (ptr >= endPtr)
01334             break;
01335     }
01336 
01337     radio.xfer(OPCODE_SET_GFSK_SYNC_WORD, 8, 0, buf);
01338     return false;
01339 }
01340 
01341 const value_item_t Radio::gfsk_syncWord_item = { _ITEM_VALUE, 17, gfsk_syncWord_print, gfsk_syncWord_write};
01342 
01343 static const char* const addrcomps[] = {
01344     "          off        ",
01345     "NodeAddress          ",
01346     "NodeAddress+broadcast",
01347     NULL
01348 };
01349 
01350 unsigned Radio::gfsk_addrcomp_read(bool forWriting)
01351 {
01352     gfskConfig4_t cfg4;
01353     radio.memRegRead(REG_ADDR_GFSK_PAYLOAD_LENGTH_B, 1, &cfg4.dword);
01354     gfsk_pp_buf[4] = cfg4.bits.addr_comp;
01355     return cfg4.bits.addr_comp;
01356 }
01357 
01358 menuMode_e Radio::gfsk_addrcomp_write(unsigned sidx)
01359 {
01360     gfsk_pp_buf[4] = sidx;
01361     radio.xfer(OPCODE_SET_PACKET_PARAM, 9, 0, gfsk_pp_buf);
01362     return MENUMODE_REDRAW;
01363 }
01364 
01365 const dropdown_item_t Radio::gfsk_addrcomp_item = { _ITEM_DROPDOWN, addrcomps, addrcomps, gfsk_addrcomp_read, gfsk_addrcomp_write};
01366 
01367 bool Radio::gfsk_varlen_read()
01368 {
01369     gfskConfig3_t cfg3;
01370     radio.memRegRead(REG_ADDR_GFSK_CFG3, 1, &cfg3.dword);
01371     gfsk_pp_buf[5] = cfg3.bits.variable_length;
01372     return cfg3.bits.variable_length;
01373 }
01374 
01375 bool Radio::gfsk_varlen_push()
01376 {
01377     gfsk_pp_buf[5] ^= 1;
01378     radio.xfer(OPCODE_SET_PACKET_PARAM, 9, 0, gfsk_pp_buf);
01379     return gfsk_pp_buf[5];
01380 }
01381 
01382 const toggle_item_t Radio::gfsk_varlen_item = { _ITEM_TOGGLE, "fixLen", "varLen", gfsk_varlen_read, gfsk_varlen_push};
01383 
01384 void Radio::gfsk_syncLen_print()
01385 {
01386     gfskConfig2_t cfg2;
01387     radio.memRegRead(REG_ADDR_GFSK_CFG2, 1, &cfg2.dword);
01388     gfsk_pp_buf[3] = cfg2.bits.sync_word_length;
01389     printf("%u", cfg2.bits.sync_word_length);
01390 }
01391 
01392 bool Radio::gfsk_syncLen_write(const char *txt)
01393 {
01394     unsigned n;
01395     if (sscanf(txt, "%u", &n) == 1) {
01396         gfsk_pp_buf[3] = n;
01397         radio.xfer(OPCODE_SET_PACKET_PARAM, 9, 0, gfsk_pp_buf);
01398     }
01399     return false;
01400 }
01401 
01402 const value_item_t Radio::gfsk_syncLen_item = { _ITEM_VALUE, 4, gfsk_syncLen_print, gfsk_syncLen_write}; 
01403 
01404 const char* const Radio::gfsk_crcType_strs[] = 
01405 {
01406     /* 0 */ "    OFF   ",
01407     /* 1 */ "1_BYTE    ",
01408     /* 2 */ "2_BYTE    ",
01409     /* 3 */ "1_BYTE_INV",
01410     /* 4 */ "2_BYTE_INV",
01411     /* 5 */ NULL
01412 };
01413 
01414 unsigned Radio::gfsk_crcType_read(bool for_writing)
01415 {
01416     unsigned ret;
01417     gfskConfig5_t cfg5;
01418     radio.memRegRead(REG_ADDR_GFSK_CFG5, 1, &cfg5.dword);
01419     // gfsk_pp_buf[7]: bit2:inv  bit1:twobyte  bit0:disabled
01420     if (cfg5.bits.crc_off)
01421         gfsk_pp_buf[7] |= 1;
01422     else
01423         gfsk_pp_buf[7] &= ~1;
01424 
01425     if (cfg5.bits.crc_size)
01426         gfsk_pp_buf[7] |= 2;
01427     else
01428         gfsk_pp_buf[7] &= ~2;
01429 
01430     if (cfg5.bits.crc_invert)
01431         gfsk_pp_buf[7] |= 4;
01432     else
01433         gfsk_pp_buf[7] &= ~4;
01434 
01435     switch (gfsk_pp_buf[7]) {
01436         case GFSK_CRC_OFF: ret = 0; break;
01437         case GFSK_CRC_1_BYTE: ret = 1; break;
01438         case GFSK_CRC_2_BYTE: ret = 2; break;
01439         case GFSK_CRC_1_BYTE_INV: ret = 3; break;
01440         case GFSK_CRC_2_BYTE_INV: ret = 4; break;
01441         default: ret = 5; break;
01442     }
01443     return ret;
01444 }
01445 
01446 menuMode_e Radio::gfsk_crcType_write(unsigned sidx)
01447 {
01448     switch (sidx) {
01449         case 0: gfsk_pp_buf[7] = GFSK_CRC_OFF; break;
01450         case 1: gfsk_pp_buf[7] = GFSK_CRC_1_BYTE; break;
01451         case 2: gfsk_pp_buf[7] = GFSK_CRC_2_BYTE; break;
01452         case 3: gfsk_pp_buf[7] = GFSK_CRC_1_BYTE_INV; break;
01453         case 4: gfsk_pp_buf[7] = GFSK_CRC_2_BYTE_INV; break;
01454     }
01455     radio.xfer(OPCODE_SET_PACKET_PARAM, 9, 0, gfsk_pp_buf);
01456     return MENUMODE_REDRAW;
01457 }
01458 
01459 const dropdown_item_t Radio::gfsk_crcType_item = { _ITEM_DROPDOWN, gfsk_crcType_strs, gfsk_crcType_strs, gfsk_crcType_read, gfsk_crcType_write };
01460 
01461 bool Radio::gfsk_dcfree_read(void)
01462 {
01463     gfskConfig5_t cfg5;
01464     radio.memRegRead(REG_ADDR_GFSK_CFG5, 1, &cfg5.dword);
01465     gfsk_pp_buf[8] = cfg5.bits.whitening_enable;
01466     return cfg5.bits.whitening_enable;
01467 }
01468 
01469 bool Radio::gfsk_dcfree_push(void)
01470 {
01471     gfsk_pp_buf[8] ^= 1;
01472     radio.xfer(OPCODE_SET_PACKET_PARAM, 9, 0, gfsk_pp_buf);
01473     return gfsk_pp_buf[8] == 1;
01474 }
01475 
01476 const toggle_item_t Radio::gfsk_dcfree_item = { _ITEM_TOGGLE, "off", "on ", gfsk_dcfree_read, gfsk_dcfree_push};
01477 
01478 void Radio::gfsk_crcinit_print()
01479 {
01480     radio.memRegRead(REG_ADDR_GFSK_CRC_INIT, 1, &gfsk_crc_Poly);
01481     printf("%04x", (unsigned)gfsk_crc_Poly);
01482 }
01483 
01484 bool Radio::gfsk_crcinit_write(const char *txt)
01485 {
01486     uint8_t buf[8];
01487     unsigned crcInit;
01488     sscanf(txt, "%x", &crcInit);
01489     gfsk_crc_initValue = crcInit;
01490     radio.to_big_endian32(gfsk_crc_initValue, buf);
01491     radio.to_big_endian32(gfsk_crc_Poly, buf+4);
01492     radio.xfer(OPCODE_SET_GFSK_CRC_PARAMS, 8, 0, buf);
01493     return false;
01494 }
01495 
01496 const value_item_t Radio::gfsk_crcinit_item = { _ITEM_VALUE, 4, gfsk_crcinit_print, gfsk_crcinit_write}; 
01497 
01498 void Radio::gfsk_crcpoly_print()
01499 {
01500     radio.memRegRead(REG_ADDR_GFSK_CRC_POLY, 1, &gfsk_crc_Poly);
01501     printf("%04x", (unsigned)gfsk_crc_Poly);
01502 }
01503 
01504 bool Radio::gfsk_crcpoly_write(const char *txt)
01505 {
01506     uint8_t buf[8];
01507     unsigned crcPoly;
01508     sscanf(txt, "%x", &crcPoly);
01509     gfsk_crc_Poly = crcPoly;
01510     radio.to_big_endian32(gfsk_crc_initValue, buf);
01511     radio.to_big_endian32(gfsk_crc_Poly, buf+4);
01512     radio.xfer(OPCODE_SET_GFSK_CRC_PARAMS, 8, 0, buf);
01513     return false;
01514 }
01515 
01516 const value_item_t Radio::gfsk_crcpoly_item = { _ITEM_VALUE, 4, gfsk_crcpoly_print, gfsk_crcpoly_write}; 
01517 
01518 const menu_t Radio::gfsk_menu[] = {
01519     { {FIRST_CHIP_MENU_ROW+2,  1},    "bps:", &gfsk_bitrate_item, FLAG_MSGTYPE_ALL },
01520     { {FIRST_CHIP_MENU_ROW+2, 15},    "bt:",       &gfsk_bt_item, FLAG_MSGTYPE_ALL },
01521     { {FIRST_CHIP_MENU_ROW+2, 23},   "rxbw:",    &gfsk_rxbw_item, FLAG_MSGTYPE_ALL },
01522     { {FIRST_CHIP_MENU_ROW+2, 39},   "fdev:",    &gfsk_fdev_item, FLAG_MSGTYPE_ALL },
01523 
01524     { {FIRST_CHIP_MENU_ROW+3,  1}, "PreambleLength:",  &gfsk_pblLen_item, FLAG_MSGTYPE_ALL },
01525     { {FIRST_CHIP_MENU_ROW+3, 21}, "PreambleDetectorLength:",  &gfsk_pblDetLen_item, FLAG_MSGTYPE_ALL },
01526     { {FIRST_CHIP_MENU_ROW+4,  1}, "syncWord:",  &gfsk_syncWord_item, FLAG_MSGTYPE_ALL },
01527     { {FIRST_CHIP_MENU_ROW+4, 29},     "bits:",  &gfsk_syncLen_item, FLAG_MSGTYPE_ALL },
01528     { {FIRST_CHIP_MENU_ROW+4, 38},      "CRC:",  &gfsk_crcType_item, FLAG_MSGTYPE_ALL },
01529     { {FIRST_CHIP_MENU_ROW+4, 55}, "AddrComp:",   &gfsk_addrcomp_item, FLAG_MSGTYPE_ALL },
01530 
01531     { {FIRST_CHIP_MENU_ROW+5,  1},        NULL,   &gfsk_varlen_item, FLAG_MSGTYPE_ALL },
01532     { {FIRST_CHIP_MENU_ROW+5, 10},   "whiten:",   &gfsk_dcfree_item, FLAG_MSGTYPE_ALL },
01533     { {FIRST_CHIP_MENU_ROW+5, 23},  "crcInit:",   &gfsk_crcinit_item, FLAG_MSGTYPE_ALL },
01534     { {FIRST_CHIP_MENU_ROW+5, 36},  "crcPoly:",   &gfsk_crcpoly_item, FLAG_MSGTYPE_ALL },
01535 
01536     { {FIRST_CHIP_MENU_ROW+6,  1},          NULL, &dbg_item, FLAG_MSGTYPE_ALL},
01537     { {0, 0}, NULL, NULL }
01538 };
01539 
01540 static const char* const lora_bwstrs[] = {
01541    /* 0 */ "  7.8KHz",
01542    /* 1 */ " 15.6KHz",
01543    /* 2 */ "31,25KHz",
01544    /* 3 */ " 62.5KHz",
01545    /* 4 */ "  125KHz",
01546    /* 5 */ "  250KHz",
01547    /* 6 */ "  500KHz",
01548    /* 7 */ " 1000KHz",
01549    /* 0 */ NULL
01550 };
01551 
01552 unsigned Radio::lora_bw_read(bool forWriting)
01553 {
01554     loraConfig0_t cfg0;
01555     radio.memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
01556     return cfg0.bits.modem_bw;
01557 }
01558 
01559 menuMode_e Radio::lora_bw_write(unsigned sidx)
01560 {
01561     lora_mp_buf[1] = sidx;
01562     radio.xfer(OPCODE_SET_MODULATION, 4, 0, lora_mp_buf);
01563     return MENUMODE_REDRAW;
01564 }
01565 
01566 const dropdown_item_t Radio::lora_bw_item = { _ITEM_DROPDOWN, lora_bwstrs, lora_bwstrs, lora_bw_read, lora_bw_write};
01567 
01568 void Radio::lora_sf_print()
01569 {
01570     loraConfig0_t cfg0;
01571     radio.memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
01572     lora_mp_buf[0] = cfg0.bits.modem_sf;
01573     printf("%u", cfg0.bits.modem_sf);
01574 }
01575 
01576 bool Radio::lora_sf_write(const char* str)
01577 {
01578     unsigned sf;
01579     if (sscanf(str, "%u", &sf) == 1) {
01580         lora_mp_buf[0] = sf;
01581         radio.xfer(OPCODE_SET_MODULATION, 4, 0, lora_mp_buf);
01582     }
01583     return false;
01584 }
01585 
01586 const value_item_t Radio::lora_sf_item = { _ITEM_VALUE, 3, lora_sf_print, lora_sf_write };
01587 
01588 void Radio::lora_pblLen_print()
01589 {
01590     unsigned pl;
01591     loraConfigC_t cfgc;
01592     radio.memRegRead(REG_ADDR_LORA_CONFIGC, 1, &cfgc.dword);
01593     printf("%u", cfgc.bits.preamble_length);
01594     pl = cfgc.bits.preamble_length;
01595     lora_pp_buf[1] = pl & 0xff;
01596     pl >>= 8;
01597     lora_pp_buf[0] = pl;
01598 }
01599 
01600 bool Radio::lora_pblLen_write(const char* txt)
01601 {
01602     unsigned n;
01603     if (sscanf(txt, "%u", &n) == 1) {
01604         radio.to_big_endian16(n, lora_pp_buf); 
01605         radio.xfer(OPCODE_SET_PACKET_PARAM, 6, 0, lora_pp_buf);
01606     }
01607     return false;
01608 }
01609 
01610 const value_item_t Radio::lora_pblLen_item = { _ITEM_VALUE, 5, lora_pblLen_print, lora_pblLen_write};
01611 
01612 bool Radio::lora_headerType_read()
01613 {
01614     loraConfig0_t cfg0;
01615     radio.memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
01616     lora_pp_buf[2] = cfg0.bits.implicit_header;
01617     return cfg0.bits.implicit_header;
01618 }
01619 
01620 bool Radio::lora_headerType_push()
01621 {
01622     bool ret;
01623     if (lora_pp_buf[2]) {
01624         lora_pp_buf[2] = 0;
01625         ret = false;
01626     } else {
01627         lora_pp_buf[2] = 1;
01628         ret = true;
01629     }
01630     radio.xfer(OPCODE_SET_PACKET_PARAM, 6, 0, lora_pp_buf);
01631     return ret;
01632 }
01633 
01634 const toggle_item_t Radio::lora_headerType_item = { _ITEM_TOGGLE, "EXPLICIT", "IMPLICIT", lora_headerType_read, lora_headerType_push};
01635 
01636 static const char* const lora_crs[] = {
01637     "short 4/5   ",
01638     "short 4/6   ",
01639     "short 4/7   ",
01640     "short 4/8   ",
01641     " long 4/5   ",
01642     " long 4/6   ",
01643     " long 4/8   ",
01644     NULL
01645 };
01646 
01647 unsigned Radio::lora_cr_read(bool forWriting)
01648 {
01649     loraConfig0_t cfg0;
01650     radio.memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
01651     lora_mp_buf[2] = cfg0.bits.coding_rate;
01652     if (lora_mp_buf[2] > 7)
01653         return 7;
01654     else
01655         return lora_mp_buf[2];
01656 }
01657 
01658 menuMode_e Radio::lora_cr_write(unsigned sidx)
01659 {
01660     lora_mp_buf[2] = sidx + 1;
01661     radio.xfer(OPCODE_SET_MODULATION, 4, 0, lora_mp_buf);
01662     return MENUMODE_REDRAW;
01663 }
01664 
01665 const dropdown_item_t Radio::lora_cr_item = { _ITEM_DROPDOWN, lora_crs, lora_crs, lora_cr_read, lora_cr_write};
01666 
01667 bool Radio::ppmOffset_read()
01668 {
01669     loraConfig0_t cfg0;
01670     radio.memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
01671     lora_mp_buf[3] = cfg0.bits.ppm_offset;
01672     return lora_mp_buf[3];
01673 }
01674 
01675 bool Radio::ppmOffset_push()
01676 {
01677     bool ret;
01678     if (lora_mp_buf[3]) {
01679         lora_mp_buf[3] = 0;
01680         ret = false;
01681     } else {
01682         lora_mp_buf[3] = 1;
01683         ret = true;
01684     }
01685     radio.xfer(OPCODE_SET_MODULATION, 4, 0, lora_mp_buf);
01686     return ret;
01687 }
01688 
01689 const toggle_item_t Radio::lora_ppmOffset_item = { _ITEM_TOGGLE, "LowDatarateOptimize", NULL, ppmOffset_read, ppmOffset_push};
01690 
01691 bool Radio::lora_crcon_read()
01692 {
01693     loraConfig0_t cfg0;
01694     radio.memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
01695     lora_pp_buf[4] = cfg0.bits.crc_on;
01696     return cfg0.bits.crc_on;
01697 }
01698 
01699 bool Radio::lora_crcon_push()
01700 {
01701     bool ret;
01702     if (lora_pp_buf[4]) {
01703         lora_pp_buf[4] = 0;
01704         ret = false;
01705     } else {
01706         lora_pp_buf[4] = 1;
01707         ret = true;
01708     }
01709     radio.xfer(OPCODE_SET_PACKET_PARAM, 6, 0, lora_pp_buf);
01710     return ret;
01711 }
01712 
01713 const toggle_item_t Radio::lora_crcon_item = { _ITEM_TOGGLE,
01714     "crc-off",
01715     " CrcOn ",
01716     lora_crcon_read,
01717     lora_crcon_push
01718 };
01719 
01720 bool Radio::lora_inviq_read()
01721 {
01722     loraConfigA_t cfgA;
01723     //loraConfigB_t cfgB;
01724     radio.memRegRead(REG_ADDR_LORA_CONFIGA, 1, &cfgA.dword);
01725     /*radio.memRegRead(REG_ADDR_LORA_CONFIGB, 1, buf);
01726     cfgB.dword = radio.from_big_endian32(buf);*/
01727     //TODO which one is RX vs TX: cfgA.bits.invertIQ, cfgB.bits.invertIQ
01728     lora_pp_buf[5] = cfgA.bits.invertIQ;
01729     /*if (cfgA.bits.invertIQ != cfgB.bits.invertIQ)
01730         log_printf("invIQ %u %u\r\n", cfgA.bits.invertIQ, cfgB.bits.invertIQ);*/
01731     return lora_pp_buf[5];
01732 }
01733 
01734 bool Radio::lora_inviq_push()
01735 {
01736     lora_pp_buf[5] ^= 1;
01737     radio.xfer(OPCODE_SET_PACKET_PARAM, 6, 0, lora_pp_buf);
01738     return lora_pp_buf[5] == 1;
01739 }
01740 
01741 const toggle_item_t Radio::lora_inviq_item = { _ITEM_TOGGLE,
01742     "    IQ    ",
01743     "invertedIQ",
01744     lora_inviq_read, lora_inviq_push
01745 };
01746 
01747 bool Radio::lora_sync_read()
01748 {
01749     loraSync_t sync;
01750     radio.memRegRead(REG_ADDR_LORA_SYNC, 1, &sync.dword);
01751     if (sync.bits.ppg_a == 2 && sync.bits.ppg_b == 4)
01752         return false;   // private
01753     else if (sync.bits.ppg_a == 6 && sync.bits.ppg_b == 8)
01754         return true;   // public
01755     else
01756         return false;   // unknown
01757     
01758 }
01759 
01760 bool Radio::lora_sync_push()
01761 {
01762     uint8_t buf;
01763     if (lora_sync_read())
01764         buf = 0;
01765     else
01766         buf = 1;
01767 
01768     radio.xfer(OPCODE_SET_LORA_PUBLIC_NETWORK, 1, 0, &buf);
01769     return buf;
01770 }
01771 
01772 const toggle_item_t Radio::lora_sync_item = { _ITEM_TOGGLE,
01773     "private",
01774     "public ",
01775     lora_sync_read,
01776     lora_sync_push
01777 };
01778 
01779 const menu_t Radio::lora_menu[] = {
01780     { {FIRST_CHIP_MENU_ROW+2,  1},   NULL,      &lora_bw_item, FLAG_MSGTYPE_ALL },
01781     { {FIRST_CHIP_MENU_ROW+2, 12},  "sf:",      &lora_sf_item, FLAG_MSGTYPE_ALL },
01782     { {FIRST_CHIP_MENU_ROW+2, 19},  "cr:",      &lora_cr_item, FLAG_MSGTYPE_ALL },
01783     { {FIRST_CHIP_MENU_ROW+2, 37},   NULL, &lora_ppmOffset_item, FLAG_MSGTYPE_ALL },
01784 
01785     { {FIRST_CHIP_MENU_ROW+3,  1}, "PreambleLength:", &lora_pblLen_item, FLAG_MSGTYPE_ALL },
01786     { {FIRST_CHIP_MENU_ROW+3, 23},              NULL, &lora_headerType_item, FLAG_MSGTYPE_ALL },
01787     { {FIRST_CHIP_MENU_ROW+3, 33},              NULL, &lora_crcon_item, FLAG_MSGTYPE_ALL },
01788     { {FIRST_CHIP_MENU_ROW+3, 43},              NULL, &lora_inviq_item, FLAG_MSGTYPE_ALL },
01789     { {FIRST_CHIP_MENU_ROW+3, 55},           "sync:", &lora_sync_item, FLAG_MSGTYPE_ALL },
01790 
01791     { {0, 0}, NULL, NULL }
01792 };
01793 
01794 void Radio::dbg_push()
01795 {
01796     log_printf("dbg\r\n");
01797 }
01798 
01799 const button_item_t Radio::dbg_item  = { _ITEM_BUTTON, "DBG", dbg_push };
01800 
01801 const button_item_t      rfswEn_item = { _ITEM_BUTTON, " RfSwEnable:", NULL};
01802 const button_item_t rfswStbyCfg_item = { _ITEM_BUTTON, "rfswStbyCfg:", NULL};
01803 const button_item_t   rfswRxCfg_item = { _ITEM_BUTTON, "  rfswRxCfg:", NULL};
01804 const button_item_t   rfswTxCfg_item = { _ITEM_BUTTON, "  rfswTxCfg:", NULL};
01805 const button_item_t rfswTxHPCfg_item = { _ITEM_BUTTON, "rfswTxHPCfg:", NULL};
01806 const button_item_t rfswGnssCfg_item = { _ITEM_BUTTON, "rfswGnssCfg:", NULL};
01807 const button_item_t rfswWifiCfg_item = { _ITEM_BUTTON, "rfswWifiCfg:", NULL};
01808 
01809 
01810 bool Radio::DIO10en_read()
01811 {
01812     dioEnable_t dio;
01813     radio.memRegRead(REG_ADDR_DIO10, 1, &dio.dword);
01814     if (dio.bits.enable)
01815         dioBuf[DIO_en_IDX] |= DIO10_BIT;
01816     else
01817         dioBuf[DIO_en_IDX] &= ~DIO10_BIT;
01818     return dio.bits.enable;
01819 }
01820 
01821 bool Radio::DIO8en_read()
01822 {
01823     dioEnable_t dio;
01824     radio.memRegRead(REG_ADDR_DIO8, 1, &dio.dword);
01825     if (dio.bits.enable)
01826         dioBuf[DIO_en_IDX] |= DIO8_BIT;
01827     else
01828         dioBuf[DIO_en_IDX] &= ~DIO8_BIT;
01829     return dio.bits.enable;
01830 }
01831 
01832 bool Radio::DIO7en_read()
01833 {
01834     dioEnable_t dio;
01835     radio.memRegRead(REG_ADDR_DIO7, 1, &dio.dword);
01836     if (dio.bits.enable)
01837         dioBuf[DIO_en_IDX] |= DIO7_BIT;
01838     else
01839         dioBuf[DIO_en_IDX] &= ~DIO7_BIT;
01840     return dio.bits.enable;
01841 }
01842 
01843 bool Radio::DIO6en_read()
01844 {
01845     dioEnable_t dio;
01846     radio.memRegRead(REG_ADDR_DIO6, 1, &dio.dword);
01847     if (dio.bits.enable)
01848         dioBuf[DIO_en_IDX] |= DIO6_BIT;
01849     else
01850         dioBuf[DIO_en_IDX] &= ~DIO6_BIT;
01851     return dio.bits.enable;
01852 }
01853 
01854 bool Radio::DIO5en_read()
01855 {
01856     dioEnable_t dio;
01857     radio.memRegRead(REG_ADDR_DIO5, 1, &dio.dword);
01858     if (dio.bits.enable)
01859         dioBuf[DIO_en_IDX] |= DIO5_BIT;
01860     else
01861         dioBuf[DIO_en_IDX] &= ~DIO5_BIT;
01862     return dio.bits.enable;
01863 }
01864 
01865 bool Radio::DIO10en_push()
01866 {
01867     dioBuf[DIO_en_IDX] ^= DIO10_BIT;
01868     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01869     return dioBuf[DIO_en_IDX] == DIO10_BIT;
01870 }
01871 
01872 bool Radio::DIO8en_push()
01873 {
01874     dioBuf[DIO_en_IDX] ^= DIO8_BIT;
01875     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01876     return dioBuf[DIO_en_IDX] == DIO8_BIT;
01877 }
01878 
01879 bool Radio::DIO7en_push()
01880 {
01881     dioBuf[DIO_en_IDX] ^= DIO7_BIT;
01882     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01883     return dioBuf[DIO_en_IDX] == DIO7_BIT;
01884 }
01885 
01886 bool Radio::DIO6en_push()
01887 {
01888     dioBuf[DIO_en_IDX] ^= DIO6_BIT;
01889     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01890     return dioBuf[DIO_en_IDX] == DIO6_BIT;
01891 }
01892 
01893 bool Radio::DIO5en_push()
01894 {
01895     dioBuf[DIO_en_IDX] ^= DIO5_BIT;
01896     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01897     return dioBuf[DIO_en_IDX] == DIO5_BIT;
01898 }
01899 
01900 const toggle_item_t Radio::DIO5en_item = { _ITEM_TOGGLE, "DIO5", NULL, DIO5en_read, DIO5en_push};
01901 const toggle_item_t Radio::DIO6en_item = { _ITEM_TOGGLE, "DIO6", NULL, DIO6en_read, DIO6en_push};
01902 const toggle_item_t Radio::DIO7en_item = { _ITEM_TOGGLE, "DIO7", NULL, DIO7en_read, DIO7en_push};
01903 const toggle_item_t Radio::DIO8en_item = { _ITEM_TOGGLE, "DIO8", NULL, DIO8en_read, DIO8en_push};
01904 const toggle_item_t Radio::DIO10en_item = { _ITEM_TOGGLE, "DIO10", NULL, DIO10en_read, DIO10en_push};
01905 
01906 bool Radio::DIO10stby_read()
01907 {
01908     return dioBuf[DIO_stby_IDX] == DIO10_BIT;
01909 }
01910 
01911 bool Radio::DIO10stby_push()
01912 {
01913     dioBuf[DIO_stby_IDX] ^= DIO10_BIT;
01914     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01915     return DIO10stby_read();
01916 }
01917 
01918 bool Radio::DIO8stby_read()
01919 {
01920     return dioBuf[DIO_stby_IDX] == DIO8_BIT;
01921 }
01922 
01923 bool Radio::DIO8stby_push()
01924 {
01925     dioBuf[DIO_stby_IDX] ^= DIO8_BIT;
01926     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01927     return DIO8stby_read();
01928 }
01929 
01930 bool Radio::DIO7stby_read()
01931 {
01932     return dioBuf[DIO_stby_IDX] == DIO7_BIT;
01933 }
01934 
01935 bool Radio::DIO7stby_push()
01936 {
01937     dioBuf[DIO_stby_IDX] ^= DIO7_BIT;
01938     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01939     return DIO7stby_read();
01940 }
01941 
01942 bool Radio::DIO6stby_read()
01943 {
01944     return dioBuf[DIO_stby_IDX] == DIO6_BIT;
01945 }
01946 
01947 bool Radio::DIO6stby_push()
01948 {
01949     dioBuf[DIO_stby_IDX] ^= DIO6_BIT;
01950     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01951     return DIO6stby_read();
01952 }
01953 
01954 bool Radio::DIO5stby_read()
01955 {
01956     return dioBuf[DIO_stby_IDX] == DIO5_BIT;
01957 }
01958 
01959 bool Radio::DIO5stby_push()
01960 {
01961     dioBuf[DIO_stby_IDX] ^= DIO5_BIT;
01962     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01963     return DIO5stby_read();
01964 }
01965 
01966 const toggle_item_t Radio::DIO5stby_item = { _ITEM_TOGGLE, "DIO5", NULL, DIO5stby_read, DIO5stby_push};
01967 const toggle_item_t Radio::DIO6stby_item = { _ITEM_TOGGLE, "DIO6", NULL, DIO6stby_read, DIO6stby_push};
01968 const toggle_item_t Radio::DIO7stby_item = { _ITEM_TOGGLE, "DIO7", NULL, DIO7stby_read, DIO7stby_push};
01969 const toggle_item_t Radio::DIO8stby_item = { _ITEM_TOGGLE, "DIO8", NULL, DIO8stby_read, DIO8stby_push};
01970 const toggle_item_t Radio::DIO10stby_item = { _ITEM_TOGGLE, "DIO10", NULL, DIO10stby_read, DIO10stby_push};
01971 
01972 bool Radio::DIO10rx_read()
01973 {
01974     return dioBuf[DIO_rx_IDX] == DIO10_BIT;
01975 }
01976 
01977 bool Radio::DIO10rx_push()
01978 {
01979     dioBuf[DIO_rx_IDX] ^= DIO10_BIT;
01980     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01981     return DIO10rx_read();
01982 }
01983 
01984 bool Radio::DIO8rx_read()
01985 {
01986     return dioBuf[DIO_rx_IDX] == DIO8_BIT;
01987 }
01988 
01989 bool Radio::DIO8rx_push()
01990 {
01991     dioBuf[DIO_rx_IDX] ^= DIO8_BIT;
01992     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
01993     return DIO8rx_read();
01994 }
01995 
01996 bool Radio::DIO7rx_read()
01997 {
01998     return dioBuf[DIO_rx_IDX] == DIO7_BIT;
01999 }
02000 
02001 bool Radio::DIO7rx_push()
02002 {
02003     dioBuf[DIO_rx_IDX] ^= DIO7_BIT;
02004     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02005     return DIO7rx_read();
02006 }
02007 
02008 bool Radio::DIO6rx_read()
02009 {
02010     return dioBuf[DIO_rx_IDX] == DIO6_BIT;
02011 }
02012 
02013 bool Radio::DIO6rx_push()
02014 {
02015     dioBuf[DIO_rx_IDX] ^= DIO6_BIT;
02016     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02017     return DIO6rx_read();
02018 }
02019 
02020 bool Radio::DIO5rx_read()
02021 {
02022     return dioBuf[DIO_rx_IDX] == DIO5_BIT;
02023 }
02024 
02025 bool Radio::DIO5rx_push()
02026 {
02027     dioBuf[DIO_rx_IDX] ^= DIO5_BIT;
02028     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02029     return DIO5rx_read();
02030 }
02031 
02032 const toggle_item_t Radio::DIO5rx_item = { _ITEM_TOGGLE, "DIO5", NULL, DIO5rx_read, DIO5rx_push};
02033 const toggle_item_t Radio::DIO6rx_item = { _ITEM_TOGGLE, "DIO6", NULL, DIO6rx_read, DIO6rx_push};
02034 const toggle_item_t Radio::DIO7rx_item = { _ITEM_TOGGLE, "DIO7", NULL, DIO7rx_read, DIO7rx_push};
02035 const toggle_item_t Radio::DIO8rx_item = { _ITEM_TOGGLE, "DIO8", NULL, DIO8rx_read, DIO8rx_push};
02036 const toggle_item_t Radio::DIO10rx_item = { _ITEM_TOGGLE, "DIO10", NULL, DIO10rx_read, DIO10rx_push};
02037 
02038 bool Radio::DIO10tx_read()
02039 {
02040     return dioBuf[DIO_tx_IDX] == DIO10_BIT;
02041 }
02042 
02043 bool Radio::DIO10tx_push()
02044 {
02045     dioBuf[DIO_tx_IDX] ^= DIO10_BIT;
02046     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02047     return DIO10tx_read();
02048 }
02049 
02050 bool Radio::DIO8tx_read()
02051 {
02052     return dioBuf[DIO_tx_IDX] == DIO8_BIT;
02053 }
02054 
02055 bool Radio::DIO8tx_push()
02056 {
02057     dioBuf[DIO_tx_IDX] ^= DIO8_BIT;
02058     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02059     return DIO8tx_read();
02060 }
02061 
02062 bool Radio::DIO7tx_read()
02063 {
02064     return dioBuf[DIO_tx_IDX] == DIO7_BIT;
02065 }
02066 
02067 bool Radio::DIO7tx_push()
02068 {
02069     dioBuf[DIO_tx_IDX] ^= DIO7_BIT;
02070     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02071     return DIO7tx_read();
02072 }
02073 
02074 bool Radio::DIO6tx_read()
02075 {
02076     return dioBuf[DIO_tx_IDX] == DIO6_BIT;
02077 }
02078 
02079 bool Radio::DIO6tx_push()
02080 {
02081     dioBuf[DIO_tx_IDX] ^= DIO6_BIT;
02082     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02083     return DIO6tx_read();
02084 }
02085 
02086 bool Radio::DIO5tx_read()
02087 {
02088     return dioBuf[DIO_tx_IDX] == DIO5_BIT;
02089 }
02090 
02091 bool Radio::DIO5tx_push()
02092 {
02093     dioBuf[DIO_tx_IDX] ^= DIO5_BIT;
02094     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02095     return DIO5tx_read();
02096 }
02097 
02098 const toggle_item_t Radio::DIO5tx_item = { _ITEM_TOGGLE, "DIO5", NULL, DIO5tx_read, DIO5tx_push};
02099 const toggle_item_t Radio::DIO6tx_item = { _ITEM_TOGGLE, "DIO6", NULL, DIO6tx_read, DIO6tx_push};
02100 const toggle_item_t Radio::DIO7tx_item = { _ITEM_TOGGLE, "DIO7", NULL, DIO7tx_read, DIO7tx_push};
02101 const toggle_item_t Radio::DIO8tx_item = { _ITEM_TOGGLE, "DIO8", NULL, DIO8tx_read, DIO8tx_push};
02102 const toggle_item_t Radio::DIO10tx_item = { _ITEM_TOGGLE, "DIO10", NULL, DIO10tx_read, DIO10tx_push};
02103 
02104 bool Radio::DIO10txhp_read()
02105 {
02106     return dioBuf[DIO_txhp_IDX] == DIO10_BIT;
02107 }
02108 
02109 bool Radio::DIO10txhp_push()
02110 {
02111     dioBuf[DIO_txhp_IDX] ^= DIO10_BIT;
02112     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02113     return DIO10txhp_read();
02114 }
02115 
02116 bool Radio::DIO8txhp_read()
02117 {
02118     return dioBuf[DIO_txhp_IDX] == DIO8_BIT;
02119 }
02120 
02121 bool Radio::DIO8txhp_push()
02122 {
02123     dioBuf[DIO_txhp_IDX] ^= DIO8_BIT;
02124     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02125     return DIO8txhp_read();
02126 }
02127 
02128 bool Radio::DIO7txhp_read()
02129 {
02130     return dioBuf[DIO_txhp_IDX] == DIO7_BIT;
02131 }
02132 
02133 bool Radio::DIO7txhp_push()
02134 {
02135     dioBuf[DIO_txhp_IDX] ^= DIO7_BIT;
02136     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02137     return DIO7txhp_read();
02138 }
02139 
02140 bool Radio::DIO6txhp_read()
02141 {
02142     return dioBuf[DIO_txhp_IDX] == DIO6_BIT;
02143 }
02144 
02145 bool Radio::DIO6txhp_push()
02146 {
02147     dioBuf[DIO_txhp_IDX] ^= DIO6_BIT;
02148     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02149     return DIO6txhp_read();
02150 }
02151 
02152 bool Radio::DIO5txhp_read()
02153 {
02154     return dioBuf[DIO_txhp_IDX] == DIO5_BIT;
02155 }
02156 
02157 bool Radio::DIO5txhp_push()
02158 {
02159     dioBuf[DIO_txhp_IDX] ^= DIO5_BIT;
02160     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02161     return DIO5txhp_read();
02162 }
02163 
02164 const toggle_item_t Radio::DIO5txhp_item = { _ITEM_TOGGLE, "DIO5", NULL, DIO5txhp_read, DIO5txhp_push};
02165 const toggle_item_t Radio::DIO6txhp_item = { _ITEM_TOGGLE, "DIO6", NULL, DIO6txhp_read, DIO6txhp_push};
02166 const toggle_item_t Radio::DIO7txhp_item = { _ITEM_TOGGLE, "DIO7", NULL, DIO7txhp_read, DIO7txhp_push};
02167 const toggle_item_t Radio::DIO8txhp_item = { _ITEM_TOGGLE, "DIO8", NULL, DIO8txhp_read, DIO8txhp_push};
02168 const toggle_item_t Radio::DIO10txhp_item = { _ITEM_TOGGLE, "DIO10", NULL, DIO10txhp_read, DIO10txhp_push};
02169 
02170 bool Radio::DIO10gnss_read()
02171 {
02172     return dioBuf[DIO_gnss_IDX] == DIO10_BIT;
02173 }
02174 
02175 bool Radio::DIO10gnss_push()
02176 {
02177     dioBuf[DIO_gnss_IDX] ^= DIO10_BIT;
02178     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02179     return DIO10gnss_read();
02180 }
02181 
02182 bool Radio::DIO8gnss_read()
02183 {
02184     return dioBuf[DIO_gnss_IDX] == DIO8_BIT;
02185 }
02186 
02187 bool Radio::DIO8gnss_push()
02188 {
02189     dioBuf[DIO_gnss_IDX] ^= DIO8_BIT;
02190     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02191     return DIO8gnss_read();
02192 }
02193 
02194 bool Radio::DIO7gnss_read()
02195 {
02196     return dioBuf[DIO_gnss_IDX] == DIO7_BIT;
02197 }
02198 
02199 bool Radio::DIO7gnss_push()
02200 {
02201     dioBuf[DIO_gnss_IDX] ^= DIO7_BIT;
02202     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02203     return DIO7gnss_read();
02204 }
02205 
02206 bool Radio::DIO6gnss_read()
02207 {
02208     return dioBuf[DIO_gnss_IDX] == DIO6_BIT;
02209 }
02210 
02211 bool Radio::DIO6gnss_push()
02212 {
02213     dioBuf[DIO_gnss_IDX] ^= DIO6_BIT;
02214     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02215     return DIO6gnss_read();
02216 }
02217 
02218 bool Radio::DIO5gnss_read()
02219 {
02220     return dioBuf[DIO_gnss_IDX] == DIO5_BIT;
02221 }
02222 
02223 bool Radio::DIO5gnss_push()
02224 {
02225     dioBuf[DIO_gnss_IDX] ^= DIO5_BIT;
02226     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02227     return DIO5gnss_read();
02228 }
02229 
02230 const toggle_item_t Radio::DIO5gnss_item = { _ITEM_TOGGLE, "DIO5", NULL, DIO5gnss_read, DIO5gnss_push};
02231 const toggle_item_t Radio::DIO6gnss_item = { _ITEM_TOGGLE, "DIO6", NULL, DIO6gnss_read, DIO6gnss_push};
02232 const toggle_item_t Radio::DIO7gnss_item = { _ITEM_TOGGLE, "DIO7", NULL, DIO7gnss_read, DIO7gnss_push};
02233 const toggle_item_t Radio::DIO8gnss_item = { _ITEM_TOGGLE, "DIO8", NULL, DIO8gnss_read, DIO8gnss_push};
02234 const toggle_item_t Radio::DIO10gnss_item = { _ITEM_TOGGLE, "DIO10", NULL, DIO10gnss_read, DIO10gnss_push};
02235 
02236 bool Radio::DIO10wifi_read()
02237 {
02238     return dioBuf[DIO_wifi_IDX] == DIO10_BIT;
02239 }
02240 
02241 bool Radio::DIO10wifi_push()
02242 {
02243     dioBuf[DIO_wifi_IDX] ^= DIO10_BIT;
02244     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02245     return DIO10wifi_read();
02246 }
02247 
02248 bool Radio::DIO8wifi_read()
02249 {
02250     return dioBuf[DIO_wifi_IDX] == DIO8_BIT;
02251 }
02252 
02253 bool Radio::DIO8wifi_push()
02254 {
02255     dioBuf[DIO_wifi_IDX] ^= DIO8_BIT;
02256     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02257     return DIO8wifi_read();
02258 }
02259 
02260 bool Radio::DIO7wifi_read()
02261 {
02262     return dioBuf[DIO_wifi_IDX] == DIO7_BIT;
02263 }
02264 
02265 bool Radio::DIO7wifi_push()
02266 {
02267     dioBuf[DIO_wifi_IDX] ^= DIO7_BIT;
02268     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02269     return DIO7wifi_read();
02270 }
02271 
02272 bool Radio::DIO6wifi_read()
02273 {
02274     return dioBuf[DIO_wifi_IDX] == DIO6_BIT;
02275 }
02276 
02277 bool Radio::DIO6wifi_push()
02278 {
02279     dioBuf[DIO_wifi_IDX] ^= DIO6_BIT;
02280     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02281     return DIO6wifi_read();
02282 }
02283 
02284 bool Radio::DIO5wifi_read()
02285 {
02286     return dioBuf[DIO_wifi_IDX] == DIO5_BIT;
02287 }
02288 
02289 bool Radio::DIO5wifi_push()
02290 {
02291     dioBuf[DIO_wifi_IDX] ^= DIO5_BIT;
02292     radio.xfer(OPCODE_SET_DIO_AS_RFSWITCH, 8, 0, dioBuf);
02293     return DIO5wifi_read();
02294 }
02295 
02296 const toggle_item_t Radio::DIO5wifi_item = { _ITEM_TOGGLE, "DIO5", NULL, DIO5wifi_read, DIO5wifi_push};
02297 const toggle_item_t Radio::DIO6wifi_item = { _ITEM_TOGGLE, "DIO6", NULL, DIO6wifi_read, DIO6wifi_push};
02298 const toggle_item_t Radio::DIO7wifi_item = { _ITEM_TOGGLE, "DIO7", NULL, DIO7wifi_read, DIO7wifi_push};
02299 const toggle_item_t Radio::DIO8wifi_item = { _ITEM_TOGGLE, "DIO8", NULL, DIO8wifi_read, DIO8wifi_push};
02300 const toggle_item_t Radio::DIO10wifi_item = { _ITEM_TOGGLE, "DIO10", NULL, DIO10wifi_read, DIO10wifi_push};
02301 
02302 const menu_t Radio::none_menu[] = {
02303     { {FIRST_CHIP_MENU_ROW+3,  1},          NULL, &rfswEn_item, FLAG_MSGTYPE_ALL},
02304     { {FIRST_CHIP_MENU_ROW+3, 14},          NULL, &DIO10en_item, FLAG_MSGTYPE_ALL},
02305     { {FIRST_CHIP_MENU_ROW+3, 21},          NULL, &DIO8en_item, FLAG_MSGTYPE_ALL},
02306     { {FIRST_CHIP_MENU_ROW+3, 26},          NULL, &DIO7en_item, FLAG_MSGTYPE_ALL},
02307     { {FIRST_CHIP_MENU_ROW+3, 32},          NULL, &DIO6en_item, FLAG_MSGTYPE_ALL},
02308     { {FIRST_CHIP_MENU_ROW+3, 38},          NULL, &DIO5en_item, FLAG_MSGTYPE_ALL},
02309 
02310     { {FIRST_CHIP_MENU_ROW+4,  1},          NULL, &rfswStbyCfg_item, FLAG_MSGTYPE_ALL},
02311     { {FIRST_CHIP_MENU_ROW+4, 14},          NULL, &DIO10stby_item, FLAG_MSGTYPE_ALL},
02312     { {FIRST_CHIP_MENU_ROW+4, 21},          NULL, &DIO8stby_item, FLAG_MSGTYPE_ALL},
02313     { {FIRST_CHIP_MENU_ROW+4, 26},          NULL, &DIO7stby_item, FLAG_MSGTYPE_ALL},
02314     { {FIRST_CHIP_MENU_ROW+4, 32},          NULL, &DIO6stby_item, FLAG_MSGTYPE_ALL},
02315     { {FIRST_CHIP_MENU_ROW+4, 38},          NULL, &DIO5stby_item, FLAG_MSGTYPE_ALL},
02316 
02317     { {FIRST_CHIP_MENU_ROW+5,  1},          NULL, &rfswRxCfg_item, FLAG_MSGTYPE_ALL},
02318     { {FIRST_CHIP_MENU_ROW+5, 14},          NULL, &DIO10rx_item, FLAG_MSGTYPE_ALL},
02319     { {FIRST_CHIP_MENU_ROW+5, 21},          NULL, &DIO8rx_item, FLAG_MSGTYPE_ALL},
02320     { {FIRST_CHIP_MENU_ROW+5, 26},          NULL, &DIO7rx_item, FLAG_MSGTYPE_ALL},
02321     { {FIRST_CHIP_MENU_ROW+5, 32},          NULL, &DIO6rx_item, FLAG_MSGTYPE_ALL},
02322     { {FIRST_CHIP_MENU_ROW+5, 38},          NULL, &DIO5rx_item, FLAG_MSGTYPE_ALL},
02323 
02324     { {FIRST_CHIP_MENU_ROW+6,  1},          NULL, &rfswTxCfg_item, FLAG_MSGTYPE_ALL},
02325     { {FIRST_CHIP_MENU_ROW+6, 14},          NULL, &DIO10tx_item, FLAG_MSGTYPE_ALL},
02326     { {FIRST_CHIP_MENU_ROW+6, 21},          NULL, &DIO8tx_item, FLAG_MSGTYPE_ALL},
02327     { {FIRST_CHIP_MENU_ROW+6, 26},          NULL, &DIO7tx_item, FLAG_MSGTYPE_ALL},
02328     { {FIRST_CHIP_MENU_ROW+6, 32},          NULL, &DIO6tx_item, FLAG_MSGTYPE_ALL},
02329     { {FIRST_CHIP_MENU_ROW+6, 38},          NULL, &DIO5tx_item, FLAG_MSGTYPE_ALL},
02330 
02331     { {FIRST_CHIP_MENU_ROW+7,  1},          NULL, &rfswTxHPCfg_item, FLAG_MSGTYPE_ALL},
02332     { {FIRST_CHIP_MENU_ROW+7, 14},          NULL, &DIO10txhp_item, FLAG_MSGTYPE_ALL},
02333     { {FIRST_CHIP_MENU_ROW+7, 21},          NULL, &DIO8txhp_item, FLAG_MSGTYPE_ALL},
02334     { {FIRST_CHIP_MENU_ROW+7, 26},          NULL, &DIO7txhp_item, FLAG_MSGTYPE_ALL},
02335     { {FIRST_CHIP_MENU_ROW+7, 32},          NULL, &DIO6txhp_item, FLAG_MSGTYPE_ALL},
02336     { {FIRST_CHIP_MENU_ROW+7, 38},          NULL, &DIO5txhp_item, FLAG_MSGTYPE_ALL},
02337 
02338     { {FIRST_CHIP_MENU_ROW+8,  1},          NULL, &rfswGnssCfg_item, FLAG_MSGTYPE_ALL},
02339     { {FIRST_CHIP_MENU_ROW+8, 14},          NULL, &DIO10gnss_item, FLAG_MSGTYPE_ALL},
02340     { {FIRST_CHIP_MENU_ROW+8, 21},          NULL, &DIO8gnss_item, FLAG_MSGTYPE_ALL},
02341     { {FIRST_CHIP_MENU_ROW+8, 26},          NULL, &DIO7gnss_item, FLAG_MSGTYPE_ALL},
02342     { {FIRST_CHIP_MENU_ROW+8, 32},          NULL, &DIO6gnss_item, FLAG_MSGTYPE_ALL},
02343     { {FIRST_CHIP_MENU_ROW+8, 38},          NULL, &DIO5gnss_item, FLAG_MSGTYPE_ALL},
02344 
02345     { {FIRST_CHIP_MENU_ROW+9,  1},          NULL, &rfswWifiCfg_item, FLAG_MSGTYPE_ALL},
02346     { {FIRST_CHIP_MENU_ROW+9, 14},          NULL, &DIO10wifi_item, FLAG_MSGTYPE_ALL},
02347     { {FIRST_CHIP_MENU_ROW+9, 21},          NULL, &DIO8wifi_item, FLAG_MSGTYPE_ALL},
02348     { {FIRST_CHIP_MENU_ROW+9, 26},          NULL, &DIO7wifi_item, FLAG_MSGTYPE_ALL},
02349     { {FIRST_CHIP_MENU_ROW+9, 32},          NULL, &DIO6wifi_item, FLAG_MSGTYPE_ALL},
02350     { {FIRST_CHIP_MENU_ROW+9, 38},          NULL, &DIO5wifi_item, FLAG_MSGTYPE_ALL},
02351 
02352     { {LAST_CHIP_MENU_ROW,  1},          NULL, &dbg_item, FLAG_MSGTYPE_ALL},
02353     { {0, 0}, NULL, NULL }
02354 };
02355 
02356 const menu_t* Radio::get_modem_sub_menu() { return NULL; }
02357 
02358 const menu_t* Radio::get_modem_menu()
02359 {
02360     pktType = radio.getPacketType();
02361 
02362     if (pktType == PACKET_TYPE_LORA)
02363         return lora_menu;
02364     else if (pktType == PACKET_TYPE_GFSK)
02365         return gfsk_menu;
02366     else
02367         return none_menu;
02368 
02369     return NULL;
02370 }
02371 
02372 void Radio::setFS()
02373 {
02374     radio.xfer(OPCODE_SET_FS, 0, 0, NULL);
02375 }
02376 
02377 void Radio::test()
02378 {
02379 }
02380 
02381 void Radio::rxDone(uint8_t size, float rssi, float snr)
02382 {
02383     RadioEvents->RxDone(size, rssi, snr);
02384 }
02385 
02386 void Radio::txDoneBottom()
02387 {
02388     if (RadioEvents->TxDone_botHalf)
02389         RadioEvents->TxDone_botHalf();
02390 }
02391 
02392 void Radio::boardInit(const RadioEvents_t* e)
02393 {
02394     uint8_t buf[4];
02395 
02396     {
02397         float default_ms = 62.5;
02398         unsigned ticks = default_ms * 32.768;
02399         radio.to_big_endian24(ticks, tcxo_buf+1);
02400     }
02401 
02402     radio.txDone = txDoneBottom;
02403     radio.rxDone = rxDone;
02404     radio.cadDone = cadDone;
02405 
02406     //radio.chipModeChange = chipModeChange;
02407     RadioEvents = e;
02408     stat_t stat;
02409     stat.word = radio.xfer(OPCODE_GET_VERSION, 0, 0, NULL);
02410     stat.word = radio.xfer(0x0000, 0, 4, buf);
02411     if (stat.bits.cmdStatus == CMD_DAT) {
02412         sprintf(chip_ver, "LR1110 %02x %02x %u.%u",
02413             buf[0], /* silicon rev */
02414             buf[1], /* use case */
02415             buf[2], /* firmware major */
02416             buf[3]  /* firmware minor */
02417         );
02418     }
02419 
02420     initRfSwDIO();
02421     readChip();
02422 }
02423 
02424 const char* const navToHostStr[] = {
02425     /*  0 */ "ok",
02426     /*  1 */ "cmd unexpected",
02427     /*  2 */ "cmd not implemented",
02428     /*  3 */ "cmd paramters invalid",
02429     /*  4 */ "message sanity check",
02430     /*  5 */ "scanning failed",
02431     /*  6 */ "no time",
02432     /*  7 */ "no satellite detected",
02433     /*  8 */ "almanac too old",
02434     /*  9 */ "alamanac update fail: crc",
02435     /* 10 */ "alamanac update fail: flash integrity",
02436     /* 11 */ "alamanac update fail: date too old",
02437     /* 12 */ "alamanac update fail: not allowed",
02438     /* 13 */ "global almanac crc error",
02439     /* 14 */ "almanac version not supported",
02440     /* 15 */ ""
02441 };
02442 
02443 struct wifidr {
02444     const char *txt;
02445     float Mbps;
02446 };
02447 
02448 const struct wifidr wifiDatarates[] = {
02449     /*   0 */ { NULL, 0},
02450     /*   1 */ { "DBPSK", 1},
02451     /*   2 */ { "DQPSK", 2},
02452     /*   3 */ { "BPSK", 6},
02453     /*   4 */ { "BPSK", 9},
02454     /*   5 */ { "QPSK", 12},
02455     /*   6 */ { "QPSK", 18},
02456     /*   7 */ { "16-QAM", 24},
02457     /*   8 */ { "16-QAM", 36},
02458     /*   9 */ { "(9)", 0},
02459     /*  10 */ { "(10)", 0},
02460     /*  11 */ { "BPSK", 6.5},
02461     /*  12 */ { "QPSK", 13},
02462     /*  13 */ { "QPSK", 19.5},
02463     /*  14 */ { "16-QAM", 26},
02464     /*  15 */ { "16-QAM", 39},
02465     /*  16 */ { "(16)", 0},
02466     /*  17 */ { "(17)", 0},
02467     /*  18 */ { "(18)", 0},
02468     /*  19 */ { "BPSK", 7.2},
02469     /*  20 */ { "QPSK", 14.4},
02470     /*  21 */ { "QPSK", 21.7},
02471     /*  22 */ { "16-QAM", 28.9},
02472     /*  23 */ { "16-QAM", 43.3},
02473 };
02474 
02475 
02476 void print_wifi_result(const uint8_t *result)
02477 {
02478     char out[96];
02479     char str[24];
02480     unsigned n, macStart;
02481     wifiType_t wt;
02482     wifiChanInfo_t ci;
02483     wt.octet = result[0];
02484     ci.octet = result[1];
02485     out[0] = 0;
02486     strcat(out, "802.11");
02487     switch (wt.bits.signal) {
02488         case 1: strcat(out, "b"); break;
02489         case 2: strcat(out, "g"); break;
02490         case 3: strcat(out, "n"); break;
02491     }
02492     sprintf(str, " %s %.1fMbps", wifiDatarates[wt.bits.datarate].txt, wifiDatarates[wt.bits.datarate].Mbps);
02493     strcat(out, str);
02494     strcat(out, " ");
02495 
02496     sprintf(str, "ch%u ", ci.bits.channelID);
02497     strcat(out, str);
02498     switch (ci.bits.channelID) {
02499         // table 10-5
02500     }
02501     strcat(out, " ");
02502     sprintf(str, "mv:%u ", ci.bits.macValidationID);
02503     strcat(out, str);
02504     switch (ci.bits.macValidationID) {
02505         case 1: strcat(out, "gateway"); break;
02506         case 2: strcat(out, "phone"); break;
02507         case 3: strcat(out, "?"); break;
02508         // table 10.8
02509     }
02510 
02511     sprintf(str, " rssi:%d ", (int8_t)result[2]);
02512     strcat(out, str);
02513 
02514     if (wifiResultFormatBasic) {
02515         macStart = 3;
02516     } else {
02517         macStart = 4;
02518     }
02519     for (n = 0; n < 6; n++) {
02520         sprintf(str, "%02x", result[n+macStart]);
02521         strcat(out, str);
02522         if (n < 5)
02523             strcat(out, ":");
02524     }
02525     strcat(out, " ");
02526 
02527 
02528     if (!wifiResultFormatBasic) {
02529         sprintf(str, "frameCtrl:%02x ", result[3]);
02530         strcat(out, str);
02531     }
02532     log_printf("%s\r\n", out);
02533 }
02534 
02535 bool Radio::service(int8_t statusRow)
02536 {
02537     irq_t irq;
02538     irq.dword = radio.service();
02539     if (irq.dword != 0) {
02540         char str[94];
02541         sprintf(str, "irq.dword:%06lx ", irq.dword);
02542         if (irq.bits.TxDone)
02543             strcat(str, "TxDone ");
02544         if (irq.bits.RxDone)
02545             strcat(str, "RxDone ");
02546         if (irq.bits.PreambleDetected)
02547             strcat(str, "PreambleDetected ");
02548         if (irq.bits.SyncHeaderValid)
02549             strcat(str, "SyncHeaderValid ");
02550         if (irq.bits.HeaderErr)
02551             strcat(str, "HeaderErr ");
02552         if (irq.bits.CadDone)
02553             strcat(str, "CadDone ");
02554         if (irq.bits.CadDetected)
02555             strcat(str, "CadDetected ");
02556         if (irq.bits.Timeout)
02557             strcat(str, "Timeout ");
02558         if (irq.bits.lowBat)
02559             strcat(str, "lowBat ");
02560         if (irq.bits.FskLenError)
02561             strcat(str, "FskLenError ");
02562         if (irq.bits.FskAddrError)
02563             strcat(str, "FskAddrError ");
02564         if (irq.bits.CmdErr) {
02565             char txt[23];
02566             sprintf(txt, "\e[31mCmdErr_%04x\e[0m ", radio.err_opcode);
02567             strcat(str, txt);
02568         }
02569         if (irq.bits.Error) {
02570             strcat(str, "\e[31mError: ");
02571             if (radio.errorStat.bits.lf_rc_calib)
02572                 strcat(str, "lf_rc_calib ");
02573             if (radio.errorStat.bits.hf_rc_calib)
02574                 strcat(str, "hf_rc_calib ");
02575             if (radio.errorStat.bits.adc_calib)
02576                 strcat(str, "adc_calib ");
02577             if (radio.errorStat.bits.pll_calib)
02578                 strcat(str, "pll_calib ");
02579             if (radio.errorStat.bits.img_calib)
02580                 strcat(str, "img_calib ");
02581             if (radio.errorStat.bits.hf_xosc_start_)
02582                 strcat(str, "hf_xosc_start ");
02583             if (radio.errorStat.bits.lf_xosc_start)
02584                 strcat(str, "lf_xosc_start ");
02585             if (radio.errorStat.bits.pll_lock)
02586                 strcat(str, "pll_lock ");
02587             if (radio.errorStat.bits.rx_adc_offset)
02588                 strcat(str, "rx_adc_offset ");
02589             strcat(str, "\e[0m");
02590         }
02591 
02592         if (irq.bits.WifiDone) {
02593             strcat(str, "WifiDone ");
02594         }
02595         if (irq.bits.GNSSDone) {
02596             strcat(str, "GNSSDone ");
02597         }
02598         log_printf("%s\r\n", str);
02599 
02600         /****************************/
02601         if (irq.bits.WifiDone) {
02602             stat_t stat;
02603             uint8_t nbResults;
02604             stat.word = radio.xfer(OPCODE_GET_WIFI_NB_RESULTS, 0, 0, NULL);
02605             stat.word = radio.xfer(0x0000, 0, 1, &nbResults);
02606             if (stat.bits.cmdStatus == CMD_DAT) {
02607                 unsigned n;
02608                 log_printf("nbResults:%u\r\n", nbResults);
02609                 for (n = 0; n < nbResults; n++) {
02610                     uint8_t buf[3];
02611                     uint8_t resultBuf[22];
02612                     buf[0] = n;
02613                     buf[1] = 1; // number of results in this read
02614                     buf[2] = wifiResultFormatBasic ? 4 : 1;
02615                     stat.word = radio.xfer(OPCODE_WIFI_READ_RESULTS, 3, 0, buf);
02616                     // basic =  9byte length
02617                     // full  = 22byte length
02618                     stat.word = radio.xfer(0x0000, 0, wifiResultFormatBasic ? 9 : 22, resultBuf);
02619                     if (stat.bits.cmdStatus == CMD_DAT)
02620                         print_wifi_result(resultBuf);
02621                     else
02622                         log_printf("readResult:%s\r\n", radio.cmdStatus_toString(stat.bits.cmdStatus));
02623                 }
02624             } else
02625                 log_printf("nbResults:%s\r\n", radio.cmdStatus_toString(stat.bits.cmdStatus));
02626         } // ..if (irq.bits.WifiDone)
02627 
02628         if (irq.bits.GNSSDone) {
02629             uint8_t gnssResultBuf[512];
02630             uint8_t buf[2];
02631             stat_t stat;
02632             unsigned resultSize;
02633             stat.word = radio.xfer(OPCODE_GNSS_GET_RESULT_SIZE, 0, 0, NULL);
02634             stat.word = radio.xfer(0x0000, 0, 2, buf);
02635             if (stat.bits.cmdStatus == CMD_DAT) {
02636                 resultSize = buf[1];
02637                 resultSize <<= 8;
02638                 resultSize |= buf[0];
02639                 log_printf("resultSize:%u\r\n", resultSize);
02640                 stat.word = radio.xfer(OPCODE_GNSS_READ_RESULTS, 0, 0, NULL);
02641                 stat.word = radio.xfer(0x0000, 0, resultSize, gnssResultBuf);
02642                 if (stat.bits.cmdStatus == CMD_DAT) {
02643                     unsigned i = 0, n;
02644                     switch (gnssResultBuf[0]) {
02645                         case 0: log_printf("navToHost:%s\r\n", navToHostStr[gnssResultBuf[0]]); break;
02646                         case 1: log_printf("navToSolver\r\n"); break;
02647                         case 2: log_printf("navToDMC\r\n"); break;
02648                         default: log_printf("nav:%u\r\n", gnssResultBuf[0]); break;
02649                     }
02650                     for (i = 0; i < resultSize; ) {
02651                         printf("%03x:", i);
02652                         for (n = 0; n < 16; n++) {
02653                             printf("%02x ", gnssResultBuf[i+n]);
02654                             if (n == 7)
02655                                 printf(" ");
02656                         }
02657                         for (n = 0; n < 16; n++) {
02658                             if (n > ' ' && n < 0x7f)
02659                                 printf("%c", gnssResultBuf[i+n]);
02660                             else
02661                                 printf(".");
02662                             if (n == 7)
02663                                 printf(" ");
02664                         }
02665                         printf("\r\n");
02666                         i += 16;
02667                     }
02668                 } else
02669                     log_printf("resultBuf:%s\r\n", radio.cmdStatus_toString(stat.bits.cmdStatus));
02670             } else
02671                 log_printf("resultSize:%s\r\n", radio.cmdStatus_toString(stat.bits.cmdStatus));
02672         } // ..if (irq.bits.GNSSDone)
02673 
02674     } // ..if (irq.dword != 0)
02675     return false;
02676 }
02677 
02678 char Radio::chip_ver[24];
02679 const char* const Radio::chipNum_str = chip_ver;
02680 
02681 const char* const Radio::opmode_select_strs[] = {
02682     "SLEEP     ", // 0
02683     "STDBY-RC  ", // 1
02684     "STDBY-XOSC", // 2
02685     "FS        ", // 3
02686     "RX        ", // 4
02687     "TX        ", // 5
02688     NULL
02689 };
02690 
02691 menuMode_e Radio::opmode_write(unsigned sel)
02692 {
02693     //stat_t stat;
02694     uint8_t buf[5];
02695 
02696     switch (sel) {
02697         case 0: //sleep
02698             {
02699                 unsigned ticks = 0;
02700                 buf[0] = 1;  // sleep config: dont wakeup, retain chip state
02701                 radio.to_big_endian24(ticks, buf+1);
02702                 /*stat.word =*/ radio.xfer(OPCODE_SET_SLEEP, 5, 0, buf);
02703             }
02704             break;
02705         case 1: // stby-rc
02706             buf[0] = 0;
02707             /*stat.word =*/ radio.xfer(OPCODE_SET_STANDBY, 1, 0, buf);
02708             break;
02709         case 2: // stby-xosc
02710             buf[0] = 1;
02711             /*stat.word =*/ radio.xfer(OPCODE_SET_STANDBY, 1, 0, buf);
02712             break;
02713         case 3: // fs
02714             setFS();
02715             break;
02716         case 4: // rx
02717             {
02718                 unsigned ticks = 0xffffff; // all 1's: receive until commanded to stop
02719                 radio.to_big_endian24(ticks, buf);
02720                 log_printf("setRx %02x %02x %02x\r\n", buf[0], buf[1], buf[2]);
02721                 /*stat.word =*/ radio.xfer(OPCODE_SET_RX, 3, 0, buf);
02722             }
02723             break;
02724         case 5: // tx
02725             {
02726                 unsigned ticks = 0; // 0 = disable-tx-timeout
02727                 radio.to_big_endian24(ticks, buf);
02728                 log_printf("setTx %02x %02x %02x\r\n", buf[0], buf[1], buf[2]);
02729                 /*stat.word =*/ radio.xfer(OPCODE_SET_TX, 3, 0, buf);
02730             }
02731             
02732             break;
02733     }
02734     return MENUMODE_REDRAW;
02735 }
02736 
02737 const char* const Radio::opmode_status_strs[] = {
02738     "SLEEP     ", // 0
02739     "STDBY-RC  ", // 1
02740     "STDBY-XOSC", // 2
02741     "FS        ", // 3
02742     "RX        ", // 4
02743     "TX        ", // 5
02744     "wifi/gnss ", // 6
02745     NULL
02746 };
02747 
02748 
02749 unsigned Radio::opmode_read(bool forWriting)
02750 {
02751     uint8_t buf[4];
02752     stat_t stat;
02753     stat.word = radio.xfer(OPCODE_GET_STATUS, 4, 0, buf);
02754     return stat.bits.chipMode;
02755 }
02756 
02757 const char* const Radio::pktType_strs[] = {
02758     "NONE   ",
02759     "GFSK   ",
02760     "LORA   ",
02761     NULL
02762 };
02763 
02764 unsigned Radio::pktType_read(bool fw)
02765 {
02766     return radio.getPacketType();
02767 }
02768 
02769 menuMode_e Radio::pktType_write(unsigned idx)
02770 {
02771     //stat_t stat;
02772     uint8_t buf = idx;
02773     /*stat.word =*/ radio.xfer(OPCODE_SET_PACKET_TYPE, 1, 0, &buf);
02774     return MENUMODE_REINIT_MENU;
02775 }
02776 
02777 bool Radio::tx_dbm_write(const char* str)
02778 {
02779     int dbm;
02780     sscanf(str, "%d", &dbm);
02781     tx_param_buf[0] = dbm;
02782     radio.xfer(OPCODE_SET_TXPARAMS, 2, 0, tx_param_buf);
02783     return false;
02784 }
02785 
02786 void Radio::tx_dbm_print()
02787 {
02788     txParamsB_t txpb;   // txpb.bits.PaSel
02789     txParamsC_t txpc;
02790     radio.memRegRead(REG_ADDR_TX_PARAMS_C, 1, &txpc.dword);
02791     radio.memRegRead(REG_ADDR_TX_PARAMS_B, 1, &txpb.dword);
02792     if (txpb.bits.PaSel)
02793         printf("%d", txpc.bits.tx_dbm - 9);
02794     else
02795         printf("%d", txpc.bits.tx_dbm - 17);
02796 }
02797 
02798 const char* Radio::tx_ramp_strs[] = {
02799     "10  ", // 0
02800     "20  ", // 1
02801     "40  ", // 2
02802     "80  ", // 3
02803     "200 ", // 4
02804     "800 ", // 5
02805     "1700", // 6
02806     "3400", // 7
02807     NULL
02808 };
02809 
02810 unsigned Radio::tx_ramp_read(bool fw)
02811 {
02812     txParamsC_t txpc;
02813     radio.memRegRead(REG_ADDR_TX_PARAMS_C, 1, &txpc.dword);
02814     return txpc.bits.pa_ramp_time;
02815 }
02816 
02817 menuMode_e Radio::tx_ramp_write(unsigned sidx)
02818 {
02819     tx_param_buf[1] = sidx;
02820     radio.xfer(OPCODE_SET_TXPARAMS, 2, 0, tx_param_buf);
02821     return MENUMODE_REDRAW;
02822 }
02823 
02824 void Radio::tx_payload_length_print()
02825 {
02826     printf("%u", get_payload_length());
02827 }
02828 
02829 
02830 #endif /* ..SX1265_H */