test sending sensor results over lora radio. Accelerometer and temp/pressure.
Serial terminal operates at 115200.
This project provides a text-based menu over serial port.
Operating the program only requires using the arrow keys, enter key to activate a control, or entering numbers.
Two sensors provided:
LIS12DH12
accelerometer operates in a continuous sampling mode. Enable control for accelerometer enables this continuous sampling, approx every 3 seconds.
LPS22HH temperature / pressure sensor operates as single shot, where pressing the control button on terminal causes single sample to be performed.
poll rate
control will enable repeated reading of pressure/temperature-sensor or photo-sensor when poll rate is greater than zero.
target must be: DISCO_L072CZ_LRWAN1
Diff: radio_sx127x.cpp
- Revision:
- 0:e1e70da93044
diff -r 000000000000 -r e1e70da93044 radio_sx127x.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio_sx127x.cpp Wed Apr 24 10:11:06 2019 -0700 @@ -0,0 +1,1752 @@ +#include "radio.h" +#ifdef SX127x_H + +const char* const Radio::chipNum_str = "SX127x"; + +const RadioEvents_t* Radio::RadioEvents; +LowPowerTimer Radio::lpt; +uint8_t Radio::bw_idx; + +RegPaRamp_t Radio::RegPaRamp; + +const char* opModes[] = { + "SLEEP ", // 0 + "STANDBY ", // 1 + "FS_TX ", // 2 + "TX ", // 3 + "FS_RX ", // 4 + "RX ", // 5 + "RX_SINGLE", // 6 + "CAD " // 7 +}; + +const char* Radio::tx_ramp_strs[] = { + "3400", // 0 + "2000", // 1 + "1000", // 2 + "500 ", // 3 + "250 ", // 4 + "125 ", // 5 + "100 ", // 6 + "62 ", // 7 + "50 ", // 8 + "40 ", // 9 + "31 ", // 10 + "25 ", // 11 + "20 ", // 12 + "15 ", // 13 + "12 ", // 14 + "10 ", // 15 + NULL +}; + +unsigned Radio::tx_ramp_read(bool fw) +{ + RegPaRamp.octet = radio.read_reg(REG_PARAMP); + return RegPaRamp.bits.PaRamp; +} + +menuMode_e Radio::tx_ramp_write(unsigned val) +{ + RegPaRamp.octet = radio.read_reg(REG_PARAMP); + + RegPaRamp.bits.PaRamp = val; + radio.write_reg(REG_PARAMP, RegPaRamp.octet); + + return MENUMODE_REDRAW; +} + +const char* const Radio::pktType_strs[] = { + "FSK ", // 0 + "OOK ", // 1 + "LORA", // 2 + NULL +}; + +unsigned Radio::pktType_read(bool fw) +{ + radio.RegOpMode.octet = radio.read_reg(REG_OPMODE); + if (radio.RegOpMode.bits.LongRangeMode) + return 2; + else + return radio.RegOpMode.bits.ModulationType; +} + +menuMode_e Radio::pktType_write(unsigned idx) +{ + if (idx == 2) { + if (!radio.RegOpMode.bits.LongRangeMode) { + /* to lora */ + radio.set_opmode(RF_OPMODE_SLEEP); + radio.RegOpMode.bits.LongRangeMode = 1; + wait_us(1000); + radio.write_reg(REG_OPMODE, radio.RegOpMode.octet); + } + } else { + if (radio.RegOpMode.bits.LongRangeMode) { + /* from lora */ + radio.set_opmode(RF_OPMODE_SLEEP); + radio.RegOpMode.bits.LongRangeMode = 0; + wait_us(1000); + radio.write_reg(REG_OPMODE, radio.RegOpMode.octet); + } + + if (radio.RegOpMode.bits.ModulationType != idx) { + radio.RegOpMode.bits.ModulationType = idx; + radio.write_reg(REG_OPMODE, radio.RegOpMode.octet); + } + } + + return MENUMODE_REINIT_MENU; +} + +void Radio::hw_reset() +{ + radio.hw_reset(); +} + +void Radio::clearIrqFlags() +{ + if (radio.RegOpMode.bits.LongRangeMode) { + radio.write_reg(REG_LR_IRQFLAGS, 0xff); // clear flags in radio + } else { + radio.write_reg(REG_FSK_IRQFLAGS1, 0x0b); + radio.write_reg(REG_FSK_IRQFLAGS2, 0x11); + } +} + +void Radio::readChip() +{ +} + +uint8_t Radio::get_payload_length() +{ + if (radio.RegOpMode.bits.LongRangeMode) { + lora.RegPayloadLength = radio.read_reg(REG_LR_PAYLOADLENGTH); + return lora.RegPayloadLength; + } else { + fsk.RegPktConfig2.word = radio.read_u16(REG_FSK_PACKETCONFIG2); + return fsk.RegPktConfig2.bits.PayloadLength; + } +} + +void Radio::set_payload_length(uint8_t len) +{ + if (radio.RegOpMode.bits.LongRangeMode) { + lora.RegPayloadLength = len; + radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength); + } else { + fsk.RegPktConfig2.bits.PayloadLength = len; + radio.write_u16(REG_FSK_PACKETCONFIG2, fsk.RegPktConfig2.word); + } +} + +void Radio::Rx() +{ + if (radio.RegOpMode.bits.LongRangeMode) + lora.start_rx(RF_OPMODE_RECEIVER); + else + fsk.start_rx(); +} + +void Radio::txPkt() +{ + if (radio.RegOpMode.bits.LongRangeMode) { + lora.RegPayloadLength = radio.read_reg(REG_LR_PAYLOADLENGTH); + lora.start_tx(lora.RegPayloadLength); + } else { + fsk.RegPktConfig2.word = radio.read_u16(REG_FSK_PACKETCONFIG2); + //log_printf("fsk payLen %u\r\n", fsk.RegPktConfig2.bits.PayloadLength); + fsk.start_tx(fsk.RegPktConfig2.bits.PayloadLength); + } +} + +void Radio::tx_carrier() +{ + radio.set_opmode(RF_OPMODE_SLEEP); + fsk.enable(false); + radio.write_u16(REG_FSK_FDEVMSB, 0); + radio.write_u16(REG_FSK_PREAMBLEMSB, 0xffff); + fsk.start_tx(8); +} + +void Radio::tx_preamble() +{ + if (radio.RegOpMode.bits.LongRangeMode) { + radio.write_u16(REG_LR_PREAMBLEMSB, 0xffff); + lora.start_tx(8); + } else { + radio.write_u16(REG_FSK_PREAMBLEMSB, 0xffff); + fsk.start_tx(8); + } +} + +bool Radio::service(int8_t statusRow) +{ + bool ret = false; + static RegIrqFlags1_t prevRegIrqFlags1; + static RegIrqFlags2_t prevRegIrqFlags2; + static us_timestamp_t prev_now; + us_timestamp_t now = lpt.read_us(); + + if (radio.RegOpMode.bits.LongRangeMode) { + const float bws[] = {7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250, 500}; + int32_t est_freq_error; + int idx, hz; + service_action_e act = lora.service(); + switch (act) { + case SERVICE_READ_FIFO: + est_freq_error = radio.read_reg(REG_LR_TEST28); + est_freq_error <<= 8; + est_freq_error += radio.read_reg(REG_LR_TEST29); + est_freq_error <<= 8; + est_freq_error += radio.read_reg(REG_LR_TEST2A); + + if (est_freq_error & 0x80000) + est_freq_error |= 0xfff00000; // extend sign from 20bit to 32bit + + //log_printf("est_freq_error:%08x\r\n", est_freq_error); + if (radio.type == SX1272) + idx = bw_idx + 7; + else + idx = bw_idx; + + hz = est_freq_error * -0.524288 * bws[idx] / 500; + log_printf("hz:%d\r\n", hz); + + RadioEvents->RxDone(lora.RegRxNbBytes, lora.get_pkt_rssi(), lora.RegPktSnrValue / 4.0); + break; + case SERVICE_TX_DONE: + if (RadioEvents->TxDone_botHalf) + RadioEvents->TxDone_botHalf(); + break; + case SERVICE_ERROR: + case SERVICE_NONE: + break; + } + + if (radio.RegOpMode.bits.Mode == RF_OPMODE_CAD) { + if (radio.dio1 || radio.dio0) { + RegIrqFlags_t irqFlags; + irqFlags.octet = 0; + log_printf("Cad: "); + if (radio.dio0) { + pc.printf("Done "); + radio.RegOpMode.bits.Mode = RF_OPMODE_STANDBY; + irqFlags.bits.CadDone = 1; + } + if (radio.dio1) { + pc.printf("Detected"); + irqFlags.bits.CadDetected = 1; + } + pc.printf("\r\n"); + radio.write_reg(REG_LR_IRQFLAGS, irqFlags.octet); + } + } + } else { + service_action_e act = fsk.service(); + switch (act) { + case SERVICE_READ_FIFO: + /*if (fsk.RegRxConfig.bits.AfcAutoOn) { + printf("%dHz ", (int)(FREQ_STEP_HZ * fsk.RegAfcValue)); + if (rssi != 0) { + printf("pkt:-%.1fdBm ", rssi / 2.0); + rssi = 0; + } + }*/ + if (fsk.RegRxConfig.bits.AfcAutoOn) + log_printf("%dHz\r\n", (int)(FREQ_STEP_HZ * fsk.RegAfcValue)); + + RadioEvents->RxDone(fsk.rx_buf_length, /*TODO rssi*/0, 0); + break; + case SERVICE_TX_DONE: + if (RadioEvents->TxDone_botHalf) + RadioEvents->TxDone_botHalf(); + break; + case SERVICE_ERROR: + case SERVICE_NONE: + break; + } + + if (statusRow > 0 && now-prev_now > 50000) { + RegIrqFlags1_t RegIrqFlags1; + RegIrqFlags2_t RegIrqFlags2; + + RegIrqFlags1.octet = radio.read_reg(REG_FSK_IRQFLAGS1); + RegIrqFlags2.octet = radio.read_reg(REG_FSK_IRQFLAGS2); + prev_now = now; + + if (RegIrqFlags1.octet != prevRegIrqFlags1.octet || RegIrqFlags2.octet != prevRegIrqFlags2.octet) { + + pc.printf("\e[%u;1f", statusRow); // set (force) cursor to row;column + + if (RegIrqFlags1.bits.ModeReady) + pc.printf("ModeReady "); + if (RegIrqFlags1.bits.RxReady) + pc.printf("RxReady "); + if (RegIrqFlags1.bits.TxReady) + pc.printf("TxReady "); + if (RegIrqFlags1.bits.PllLock) + pc.printf("PllLock "); + if (RegIrqFlags1.bits.Rssi) + pc.printf("Rssi "); + if (RegIrqFlags1.bits.Timeout) + pc.printf("Timeout "); + if (RegIrqFlags1.bits.PreambleDetect) + pc.printf("PreambleDetect "); + if (RegIrqFlags1.bits.SyncAddressMatch) + pc.printf("SyncAddressMatch "); + + pc.printf(" | "); + if (RegIrqFlags2.bits.FifoFull) + pc.printf("FifoFull "); + if (RegIrqFlags2.bits.FifoEmpty) + pc.printf("FifoEmpty "); + if (RegIrqFlags2.bits.FifoLevel) + pc.printf("FifoLevel "); + if (RegIrqFlags2.bits.FifoOverrun) + pc.printf("FifoOverrun "); + if (RegIrqFlags2.bits.PacketSent) + pc.printf("PacketSent "); + if (RegIrqFlags2.bits.PayloadReady) + pc.printf("PayloadReady "); + if (RegIrqFlags2.bits.CrcOk) + pc.printf("CrcOk "); + if (RegIrqFlags2.bits.LowBat) + pc.printf("LowBat "); + + prevRegIrqFlags1.octet = RegIrqFlags1.octet; + prevRegIrqFlags2.octet = RegIrqFlags2.octet; + + pc.printf("\e[K"); + ret = true; + } // ..if irq flag changed + } // ..if (++cnt > X) + } // ..!radio.RegOpMode.bits.LongRangeMode + + return ret; +} + +void Radio::setFS() +{ + radio.set_opmode(RF_OPMODE_SYNTHESIZER_RX); +} + +const menu_t* Radio::get_modem_sub_menu() +{ + radio.RegOpMode.octet = radio.read_reg(REG_OPMODE); + if (radio.RegOpMode.bits.LongRangeMode) { + return NULL; + } else { + if (radio.RegOpMode.bits.ModulationType == 1) { + fsk.RegOokPeak.octet = radio.read_reg(REG_FSK_OOKPEAK); + if (fsk.RegOokPeak.bits.OokThreshType == 0) { + return ook_fixed_menu; + } else if (fsk.RegOokPeak.bits.OokThreshType == 1) { + return ook_peak_menu; + } else if (fsk.RegOokPeak.bits.OokThreshType == 2) { + return ook_average_menu; + } + } else + return NULL; + } + + return NULL; +} + +const menu_t* Radio::get_modem_menu() +{ + radio.RegOpMode.octet = radio.read_reg(REG_OPMODE); + + if (radio.RegOpMode.bits.LongRangeMode) { + return lora_menu; + } else { + if (radio.RegOpMode.bits.ModulationType == 0) + return fsk_menu; + else { + return ook_menu; + } + } +} + +void Radio::tx_payload_length_print() +{ + pc.printf("%u", get_payload_length()); +} + +bool Radio::tx_payload_length_write(const char* txt) +{ + unsigned len; + + sscanf(txt, "%u", &len); + //log_printf("scanned %u from \"%s\"\r\n", len, txt); + + set_payload_length(len); + + return false; +} + +const char* const Radio::opmode_status_strs[] = { + "SLEEP ", // 0 + "STANDBY ", // 1 + "FS_TX ", // 2 + "TX ", // 3 + "FS_RX ", // 4 + "RX ", // 5 + "RX_SINGLE", // 6 + "CAD ", // 7 + NULL +}; + +const char* const Radio::opmode_select_strs[] = { + "SLEEP ", // 0 + "STANDBY ", // 1 + "FS_TX ", // 2 + "TX ", // 3 + "FS_RX ", // 4 + "RX ", // 5 + "RX_SINGLE", // 6 + "CAD ", // 7 + NULL +}; + +unsigned Radio::opmode_read(bool forWriting) +{ + radio.RegOpMode.octet = radio.read_reg(REG_OPMODE); + return radio.RegOpMode.bits.Mode; +} + +menuMode_e Radio::opmode_write(unsigned sel) +{ + radio.RegOpMode.bits.Mode = sel; + radio.write_reg(REG_OPMODE, radio.RegOpMode.octet); + + return MENUMODE_REDRAW; +} + +void Radio::ocp_print(void) +{ + unsigned i; + + radio.RegOcp.octet = radio.read_reg(REG_OCP); + if (radio.RegOcp.bits.OcpTrim < 16) + i = 45 + (5 * radio.RegOcp.bits.OcpTrim); + else if (radio.RegOcp.bits.OcpTrim < 28) + i = (10 * radio.RegOcp.bits.OcpTrim) - 30; + else + i = 240; + + pc.printf("%u", i); +} + +bool Radio::ocp_write(const char* txt) +{ + unsigned i; + + sscanf(txt, "%u", &i); + + if (i < 130) + radio.RegOcp.bits.OcpTrim = (i - 45) / 5; + else + radio.RegOcp.bits.OcpTrim = (i + 30) / 10; + + radio.write_reg(REG_OCP, radio.RegOcp.octet); + + return MENUMODE_REDRAW; +} + +const value_item_t Radio::ocp_item = { _ITEM_VALUE, 4, ocp_print, ocp_write}; + +static const char* const lora_bws_1276[] = { + " 7.8KHz", // 0 + " 10.4KHz", // 1 + " 15.6KHz", // 2 + " 20.8KHz", // 3 + "31.25KHz", // 4 + " 41.7KHz", // 5 + " 62.5KHz", // 6 + " 125KHz", // 7 + " 250KHz", // 8 + " 500KHz", // 9 + NULL +}; +static const char* const lora_bws_1272[] = { + "125KHz", // 0 + "250KHz", // 1 + "500KHz", // 2 + NULL +}; + +unsigned Radio::lora_bw_read(bool fw) +{ + bw_idx = lora.getBw(); + return bw_idx; +} + +menuMode_e Radio::lora_bw_write(unsigned sidx) +{ + lora.setBw(sidx); + bw_idx = sidx; + + return MENUMODE_REDRAW; +} + +dropdown_item_t Radio::lora_bw_item = { _ITEM_DROPDOWN, NULL, NULL, lora_bw_read, lora_bw_write}; + +void Radio::lora_sf_print() +{ + pc.printf("%u", lora.getSf()); +} + +bool Radio::lora_sf_write(const char* txt) +{ + unsigned sf; + + sscanf(txt, "%u", &sf); + lora.setSf(sf); + + return false; +} + +const value_item_t Radio::lora_sf_item = { _ITEM_VALUE, 3, lora_sf_print, lora_sf_write }; + +const char* const lora_crs[] = { + "4/5", // 0 + "4/6", // 1 + "4/7", // 2 + "4/8", // 3 + NULL +}; + +unsigned Radio::lora_cr_read(bool) +{ + return lora.getCodingRate(false); +} + +menuMode_e Radio::lora_cr_write(unsigned sidx) +{ + lora.setCodingRate(sidx); + + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::lora_cr_item = { _ITEM_DROPDOWN, lora_crs, lora_crs, lora_cr_read, lora_cr_write}; + +void Radio::lora_pblLen_print() +{ + lora.RegPreamble = radio.read_u16(REG_LR_PREAMBLEMSB); + pc.printf("%u", lora.RegPreamble); +} + +bool Radio::lora_pblLen_write(const char* str) +{ + unsigned n; + + sscanf(str, "%u", &n); + + lora.RegPreamble = n; + radio.write_u16(REG_LR_PREAMBLEMSB, lora.RegPreamble); + + return false; +} + +const value_item_t Radio::lora_pblLen_item = { _ITEM_VALUE, 5, lora_pblLen_print, lora_pblLen_write}; + +static const char* const lora_fixlen[] = { + "EXPLICIT", // 0 + "IMPLICIT", // 1 + NULL +}; + +unsigned Radio::lora_fixlen_read(bool f) +{ + if (lora.getHeaderMode()) + return 1; + else + return 0; +} + +menuMode_e Radio::lora_fixlen_write(unsigned sidx) +{ + lora.setHeaderMode(sidx == 1); // true = implicit + + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::lora_fixlen_item = { _ITEM_DROPDOWN, lora_fixlen, lora_fixlen, lora_fixlen_read, lora_fixlen_write}; + +bool Radio::lora_crcon_read() +{ + return lora.getRxPayloadCrcOn(); +} + +bool Radio::lora_crcon_push() +{ + lora.setRxPayloadCrcOn(!lora.getRxPayloadCrcOn()); + return lora.getRxPayloadCrcOn(); +} + +const toggle_item_t Radio::lora_crcon_item = { _ITEM_TOGGLE, "CrcOn", NULL, lora_crcon_read, lora_crcon_push}; + +bool Radio::lora_iqinvTX_read() +{ + lora.RegTest33.octet = radio.read_reg(REG_LR_TEST33); + return !lora.RegTest33.bits.chirp_invert_tx; +} + +bool Radio::lora_iqinvTX_push() +{ + lora.invert_tx(lora.RegTest33.bits.chirp_invert_tx); + return !lora.RegTest33.bits.chirp_invert_tx; +} + +const toggle_item_t Radio::lora_iqinvTX_item = { _ITEM_TOGGLE, "iqInvTX", NULL, lora_iqinvTX_read, lora_iqinvTX_push}; + +bool Radio::lora_iqinvRX_read() +{ + lora.RegTest33.octet = radio.read_reg(REG_LR_TEST33); + return lora.RegTest33.bits.invert_i_q; +} + +bool Radio::lora_iqinvRX_push() +{ + lora.invert_rx(!lora.RegTest33.bits.invert_i_q); + lora.RegTest33.octet = radio.read_reg(REG_LR_TEST33); + return lora.RegTest33.bits.invert_i_q; +} + +const toggle_item_t Radio::lora_iqinvRX_item = { _ITEM_TOGGLE, "iqInvRX", NULL, lora_iqinvRX_read, lora_iqinvRX_push}; + +void Radio::lora_ppg_print() +{ + pc.printf("%02x", radio.read_reg(REG_LR_SYNC_BYTE)); +} + +bool Radio::lora_ppg_write(const char* str) +{ + unsigned ppg; + sscanf(str, "%x", &ppg); + + radio.write_reg(REG_LR_SYNC_BYTE, ppg); + + return false; +} + +const value_item_t Radio::lora_ppg_item = { _ITEM_VALUE, 4, lora_ppg_print, lora_ppg_write}; + +void Radio::cadrx_push() +{ + if (radio.RegDioMapping1.bits.Dio0Mapping != 2 || radio.RegDioMapping1.bits.Dio1Mapping != 2) { + radio.RegDioMapping1.bits.Dio0Mapping = 2; // DIO0 to CadDone + radio.RegDioMapping1.bits.Dio1Mapping = 2; // DIO1 to CadDetected + radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet); + } + + radio.set_opmode(RF_OPMODE_CAD); +} + +const button_item_t Radio::lora_cadrx_item = { _ITEM_BUTTON, "CADRX", cadrx_push }; + +const menu_t Radio::lora_menu[] = { + { {FIRST_CHIP_MENU_ROW, 22}, "bw:", &lora_bw_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW, 35}, "sf:", &lora_sf_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW, 42}, "cr:", &lora_cr_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW, 50}, "PreambleLength:", &lora_pblLen_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+1, 1}, NULL, &lora_fixlen_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 10}, NULL, &lora_crcon_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 20}, NULL, &lora_iqinvTX_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 30}, NULL, &lora_iqinvRX_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 40}, "ppg:", &lora_ppg_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+2, 1}, NULL, &lora_cadrx_item, FLAG_MSGTYPE_ALL }, + + { {0, 0}, NULL, NULL } +}; + +void Radio::fsk_ook_bps_print(void) +{ + pc.printf("%lu", fsk.get_bitrate()); +} + +bool Radio::fsk_ook_bps_write(const char* txt) +{ + unsigned bps; + + sscanf(txt, "%u", &bps); + fsk.set_bitrate(bps); + + return false; +} + +const value_item_t Radio::fsk_ook_bitrate_item = { _ITEM_VALUE, 8, fsk_ook_bps_print, fsk_ook_bps_write }; + +void Radio::gfsk_fdev_print(void) +{ + pc.printf("%lu", fsk.get_tx_fdev_hz()); + +} + +bool Radio::gfsk_fdev_write(const char* txt) +{ + unsigned hz; + + sscanf(txt, "%u", &hz); + + fsk.set_tx_fdev_hz(hz); + + return false; +} + +const value_item_t Radio::gfsk_fdev_item = { _ITEM_VALUE, 8, gfsk_fdev_print, gfsk_fdev_write}; + +const char* const gfsk_bts[] = { + "off", // 0 + "1.0", // 1 + "0.5", // 2 + "0.3", // 3 + NULL +}; + +const char* const ook_bts[] = { + "off ", // 0 + "bitRate ", // 1 + "2*bitRate", // 2 + NULL +}; + +unsigned Radio::bt_read(bool forWriting) +{ + if (radio.type == SX1276) { + RegPaRamp.octet = radio.read_reg(REG_PARAMP); + return RegPaRamp.bits.ModulationShaping; + } else if (radio.type == SX1272) { + radio.RegOpMode.octet = radio.read_reg(REG_OPMODE); + return radio.RegOpMode.bits.ModulationShaping; + } + return 3; +} + +menuMode_e Radio::bt_write(unsigned sel) +{ + if (radio.type == SX1276) { + RegPaRamp.bits.ModulationShaping = sel; + radio.write_reg(REG_PARAMP, RegPaRamp.octet); + } else if (radio.type == SX1272) { + radio.RegOpMode.bits.ModulationShaping = sel; + radio.write_reg(REG_OPMODE, radio.RegOpMode.octet); + } + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::gfsk_bt_item = { _ITEM_DROPDOWN, gfsk_bts, gfsk_bts, bt_read, bt_write}; +const dropdown_item_t Radio::ook_bt_item = { _ITEM_DROPDOWN, ook_bts, ook_bts, bt_read, bt_write}; + +bool Radio::paSelect_read() +{ + radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG); + return radio.RegPaConfig.bits.PaSelect; +} + +bool Radio::paSelect_push() +{ + radio.RegPaConfig.bits.PaSelect ^= 1; + radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet); + return radio.RegPaConfig.bits.PaSelect; +} + +const toggle_item_t Radio::paSelect_item = { _ITEM_TOGGLE, + "RFO ", // 0 + "PA_BOOST", // 1 + paSelect_read, paSelect_push +}; + +const char* const rxbws[] = { + " 2.6", // 0 + " 3.1", // 1 + " 3.9", // 2 + " 5.2", // 3 + " 6.3", // 4 + " 7.8", // 5 + " 10.4", // 6 + " 12.5", // 7 + " 15.6", // 8 + " 20.8", // 9 + " 25.0", // 10 + " 31.3", // 11 + " 41.7", // 12 + " 50.0", // 13 + " 62.5", // 14 + " 83.3", // 15 + "100.0", // 16 + "125.0", // 17 + "166.7", // 18 + "200.0", // 19 + "250.0", // 20 + NULL +}; + +unsigned Radio::bw_read(uint8_t regAddr) +{ + RegRxBw_t reg_bw; + + reg_bw.octet = radio.read_reg(regAddr); + + switch (reg_bw.bits.Exponent) { + case 7: + if (reg_bw.bits.Mantissa == 2) + return 0; + if (reg_bw.bits.Mantissa == 1) + return 1; + if (reg_bw.bits.Mantissa == 0) + return 2; + break; + case 6: + if (reg_bw.bits.Mantissa == 2) + return 3; + if (reg_bw.bits.Mantissa == 1) + return 4; + if (reg_bw.bits.Mantissa == 0) + return 5; + break; + case 5: + if (reg_bw.bits.Mantissa == 2) + return 6; + if (reg_bw.bits.Mantissa == 1) + return 7; + if (reg_bw.bits.Mantissa == 0) + return 8; + break; + case 4: + if (reg_bw.bits.Mantissa == 2) + return 9; + if (reg_bw.bits.Mantissa == 1) + return 10; + if (reg_bw.bits.Mantissa == 0) + return 11; + break; + case 3: + if (reg_bw.bits.Mantissa == 2) + return 12; + if (reg_bw.bits.Mantissa == 1) + return 13; + if (reg_bw.bits.Mantissa == 0) + return 14; + break; + case 2: + if (reg_bw.bits.Mantissa == 2) + return 15; + if (reg_bw.bits.Mantissa == 1) + return 16; + if (reg_bw.bits.Mantissa == 0) + return 17; + break; + case 1: + if (reg_bw.bits.Mantissa == 2) + return 18; + if (reg_bw.bits.Mantissa == 1) + return 19; + if (reg_bw.bits.Mantissa == 0) + return 20; + break; + } + + return 21; +} + +unsigned Radio::rxbw_read(bool) +{ + return bw_read(REG_FSK_RXBW); +} + +unsigned Radio::afcbw_read(bool) +{ + return bw_read(REG_FSK_AFCBW); +} + +void Radio::bw_write(unsigned sidx, uint8_t regAddr) +{ + RegRxBw_t reg_bw; + + reg_bw.octet = radio.read_reg(regAddr); + + switch (sidx) { + case 0: + reg_bw.bits.Mantissa = 2; + reg_bw.bits.Exponent = 7; + break; + case 1: + reg_bw.bits.Mantissa = 1; + reg_bw.bits.Exponent = 7; + break; + case 2: + reg_bw.bits.Mantissa = 0; + reg_bw.bits.Exponent = 7; + break; + case 3: + reg_bw.bits.Mantissa = 2; + reg_bw.bits.Exponent = 6; + break; + case 4: + reg_bw.bits.Mantissa = 1; + reg_bw.bits.Exponent = 6; + break; + case 5: + reg_bw.bits.Mantissa = 0; + reg_bw.bits.Exponent = 6; + break; + case 6: + reg_bw.bits.Mantissa = 2; + reg_bw.bits.Exponent = 5; + break; + case 7: + reg_bw.bits.Mantissa = 1; + reg_bw.bits.Exponent = 5; + break; + case 8: + reg_bw.bits.Mantissa = 0; + reg_bw.bits.Exponent = 5; + break; + case 9: + reg_bw.bits.Mantissa = 2; + reg_bw.bits.Exponent = 4; + break; + case 10: + reg_bw.bits.Mantissa = 1; + reg_bw.bits.Exponent = 4; + break; + case 11: + reg_bw.bits.Mantissa = 0; + reg_bw.bits.Exponent = 4; + break; + case 12: + reg_bw.bits.Mantissa = 2; + reg_bw.bits.Exponent = 3; + break; + case 13: + reg_bw.bits.Mantissa = 1; + reg_bw.bits.Exponent = 3; + break; + case 14: + reg_bw.bits.Mantissa = 0; + reg_bw.bits.Exponent = 3; + break; + case 15: + reg_bw.bits.Mantissa = 2; + reg_bw.bits.Exponent = 2; + break; + case 16: + reg_bw.bits.Mantissa = 1; + reg_bw.bits.Exponent = 2; + break; + case 17: + reg_bw.bits.Mantissa = 0; + reg_bw.bits.Exponent = 2; + break; + case 18: + reg_bw.bits.Mantissa = 2; + reg_bw.bits.Exponent = 1; + break; + case 19: + reg_bw.bits.Mantissa = 1; + reg_bw.bits.Exponent = 1; + break; + case 20: + reg_bw.bits.Mantissa = 0; + reg_bw.bits.Exponent = 1; + break; + } + + radio.write_reg(regAddr, reg_bw.octet); +} + +menuMode_e Radio::rxbw_write(unsigned sidx) +{ + bw_write(sidx, REG_FSK_RXBW); + return MENUMODE_REDRAW; +} + +menuMode_e Radio::afcbw_write(unsigned sidx) +{ + bw_write(sidx, REG_FSK_AFCBW); + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::rxbw_item = { _ITEM_DROPDOWN, rxbws, rxbws, rxbw_read, rxbw_write}; +const dropdown_item_t Radio::afcbw_item = { _ITEM_DROPDOWN, rxbws, rxbws, afcbw_read, afcbw_write}; + +void Radio::pblLen_print() +{ + pc.printf("%u", radio.read_u16(REG_FSK_PREAMBLEMSB)); +} + +bool Radio::pblLen_write(const char* txt) +{ + unsigned n; + sscanf(txt, "%u", &n); + radio.write_u16(REG_FSK_PREAMBLEMSB, n); + return false; +} + +const value_item_t Radio::pblLen_item = { _ITEM_VALUE, 6, pblLen_print, pblLen_write}; + + +const char* const rxTriggers[] = { + "off ", // 0 + "RSSI ", // 1 + "Preamble ", // 2 + "RSSI+Preamble", // 3 + NULL +}; + +unsigned Radio::rxTrigger_read(bool fw) +{ + fsk.RegRxConfig.octet = radio.read_reg(REG_FSK_RXCONFIG); + return fsk.RegRxConfig.bits.RxTrigger; +} + +menuMode_e Radio::rxTrigger_write(unsigned sidx) +{ + fsk.RegRxConfig.bits.RxTrigger = sidx; + radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet); + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::rxTrigger_item = { _ITEM_DROPDOWN, rxTriggers, rxTriggers, rxTrigger_read, rxTrigger_write}; + +bool Radio::AgcAutoOn_read() +{ + fsk.RegRxConfig.octet = radio.read_reg(REG_FSK_RXCONFIG); + return fsk.RegRxConfig.bits.AgcAutoOn; +} + +bool Radio::AgcAutoOn_push() +{ + fsk.RegRxConfig.bits.AgcAutoOn ^= 1; + radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet); + return fsk.RegRxConfig.bits.AgcAutoOn; +} + +bool Radio::AfcAutoOn_read() +{ + fsk.RegRxConfig.octet = radio.read_reg(REG_FSK_RXCONFIG); + return fsk.RegRxConfig.bits.AfcAutoOn; +} + +bool Radio::AfcAutoOn_push() +{ + fsk.RegRxConfig.bits.AfcAutoOn ^= 1; + radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet); + return fsk.RegRxConfig.bits.AfcAutoOn; +} + +const toggle_item_t Radio::agcautoon_item = { _ITEM_TOGGLE, "AgcAutoOn", NULL, AgcAutoOn_read, AgcAutoOn_push}; + +const toggle_item_t Radio::afcautoon_item = { _ITEM_TOGGLE, "AfcAutoOn", NULL, AfcAutoOn_read, AfcAutoOn_push}; + +bool Radio::RestartRxOnCollision_read() +{ + fsk.RegRxConfig.octet = radio.read_reg(REG_FSK_RXCONFIG); + return fsk.RegRxConfig.bits.RestartRxOnCollision; +} + +bool Radio::RestartRxOnCollision_push() +{ + fsk.RegRxConfig.bits.RestartRxOnCollision ^= 1; + radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet); + return fsk.RegRxConfig.bits.RestartRxOnCollision; +} + +const toggle_item_t Radio::RestartRxOnCollision_item = { _ITEM_TOGGLE, + "RestartRxOnCollision", NULL, + RestartRxOnCollision_read, RestartRxOnCollision_push +}; + +void Radio::RestartRxWithPllLock_push() +{ + fsk.RegRxConfig.bits.RestartRxWithPllLock = 1; + radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet); + fsk.RegRxConfig.bits.RestartRxWithPllLock = 0; +} + +const button_item_t Radio::RestartRxWithPllLock_item = { _ITEM_BUTTON, + "RestartRxWithPllLock", + RestartRxWithPllLock_push +}; + +void Radio::RestartRxWithoutPllLock_push() +{ + fsk.RegRxConfig.bits.RestartRxWithoutPllLock = 1; + radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet); + fsk.RegRxConfig.bits.RestartRxWithoutPllLock = 0; +} + +const button_item_t Radio::RestartRxWithoutPllLock_item = { _ITEM_BUTTON, + "RestartRxWithoutPllLock", + RestartRxWithoutPllLock_push +}; + +bool Radio::AfcAutoClearOn_read(void) +{ + fsk.RegAfcFei.octet = radio.read_reg(REG_FSK_AFCFEI); + return fsk.RegAfcFei.bits.AfcAutoClearOn; +} + +bool Radio::AfcAutoClearOn_push(void) +{ + fsk.RegAfcFei.bits.AfcAutoClearOn ^= 1; + radio.write_reg(REG_FSK_AFCFEI, fsk.RegAfcFei.octet); + return fsk.RegAfcFei.bits.AfcAutoClearOn; +} + +const toggle_item_t Radio::AfcAutoClearOn_item = { _ITEM_TOGGLE, "AfcAutoClearOn", NULL, AfcAutoClearOn_read, AfcAutoClearOn_push}; + +void Radio::AgcStart_push() +{ + fsk.RegAfcFei.bits.AgcStart = 1; + radio.write_reg(REG_FSK_AFCFEI, fsk.RegAfcFei.octet); + fsk.RegAfcFei.bits.AgcStart = 1; +} + +const button_item_t Radio::AgcStart_item = { _ITEM_BUTTON, "AgcStart", AgcStart_push}; + +void Radio::AfcClear_push() +{ + fsk.RegAfcFei.bits.AfcClear = 1; + radio.write_reg(REG_FSK_AFCFEI, fsk.RegAfcFei.octet); + fsk.RegAfcFei.bits.AfcClear = 0; +} +const button_item_t Radio::AfcClear_item = { _ITEM_BUTTON, "AfcClear", AfcClear_push}; + +void Radio::syncWord_print(void) +{ + unsigned n, stop; + + fsk.RegSyncConfig.octet = radio.read_reg(REG_FSK_SYNCCONFIG); + + stop = fsk.RegSyncConfig.bits.SyncSize + 1; + for (n = 0; n < stop; n++) { + pc.printf("%02x", radio.read_reg(REG_FSK_SYNCVALUE1+n)); + } +} + +bool Radio::syncWord_write(const char* txt) +{ + const char* ptr; + const char* endPtr; + unsigned o, n = 0; + + endPtr = txt + strlen(txt); + for (ptr = txt; sscanf(ptr, "%02x", &o) == 1; ) { + radio.write_reg(REG_FSK_SYNCVALUE1+n, o); + n++; + ptr += 2; + if (ptr >= endPtr) + break; + } + + fsk.RegSyncConfig.bits.SyncSize = n - 1; + radio.write_reg(REG_FSK_SYNCCONFIG, fsk.RegSyncConfig.octet); + + return false; +} + +const value_item_t Radio::syncWord_item = { _ITEM_VALUE, 17, syncWord_print, syncWord_write}; + +void Radio::syncSize_print(void) +{ + fsk.RegSyncConfig.octet = radio.read_reg(REG_FSK_SYNCCONFIG); + + pc.printf("%u", fsk.RegSyncConfig.bits.SyncSize + 1); +} + +bool Radio::syncSize_write(const char* txt) +{ + unsigned n; + sscanf(txt, "%u", &n); + if (n > 0) { + fsk.RegSyncConfig.bits.SyncSize = n - 1; + radio.write_reg(REG_FSK_SYNCCONFIG, fsk.RegSyncConfig.octet); + } + return false; +} + +const value_item_t Radio::syncSize_item = { _ITEM_VALUE, 2, syncSize_print, syncSize_write}; + +bool Radio::SyncOn_read() +{ + fsk.RegSyncConfig.octet = radio.read_reg(REG_FSK_SYNCCONFIG); + return fsk.RegSyncConfig.bits.SyncOn; +} + +bool Radio::SyncOn_push() +{ + fsk.RegSyncConfig.bits.SyncOn ^= 1; + radio.write_reg(REG_FSK_SYNCCONFIG, fsk.RegSyncConfig.octet); + return fsk.RegSyncConfig.bits.SyncOn; +} + +const toggle_item_t Radio::syncOn_item = { _ITEM_TOGGLE, "SyncOn", NULL, SyncOn_read, SyncOn_push}; + +bool Radio::fsk_pktfmt_read() +{ + fsk.RegPktConfig1.octet = radio.read_reg(REG_FSK_PACKETCONFIG1); + return fsk.RegPktConfig1.bits.PacketFormatVariable; +} + +bool Radio::fsk_pktfmt_push() +{ + fsk.RegPktConfig1.bits.PacketFormatVariable ^= 1; + radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet); + return fsk.RegPktConfig1.bits.PacketFormatVariable; +} + +const toggle_item_t Radio::fskook_pktfmt_item = { _ITEM_TOGGLE, + "fixed ", + "variable", + fsk_pktfmt_read, fsk_pktfmt_push +}; + + +void Radio::rssiOffset_print(void) +{ + int ro; + fsk.RegRssiConfig.octet = radio.read_reg(REG_FSK_RSSICONFIG); + ro = fsk.RegRssiConfig.bits.RssiOffset; + pc.printf("%d", ro); +} + +bool Radio::rssiOffset_write(const char* txt) +{ + int ro; + sscanf(txt, "%d", &ro); + fsk.RegRssiConfig.bits.RssiOffset = ro; + radio.write_reg(REG_FSK_RSSICONFIG, fsk.RegRssiConfig.octet); + return false; +} + +const value_item_t Radio::rssiOffset_item = { _ITEM_VALUE, 2, rssiOffset_print, rssiOffset_write}; + +const char* const rssiSmoothings[] = { + "2 ", // 0 + "4 ", // 1 + "8 ", // 2 + "16 ", // 3 + "32 ", // 4 + "64 ", // 5 + "128", // 6 + "256", // 7 + NULL +}; + +unsigned Radio::rssiSmoothing_read(bool fw) +{ + fsk.RegRssiConfig.octet = radio.read_reg(REG_FSK_RSSICONFIG); + return fsk.RegRssiConfig.bits.RssiSmoothing; +} + +menuMode_e Radio::rssiSmoothing_write(unsigned sidx) +{ + radio.write_reg(REG_FSK_RSSICONFIG, fsk.RegRssiConfig.octet); + fsk.RegRssiConfig.bits.RssiSmoothing = sidx; + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::rssiSmoothing_item = { _ITEM_DROPDOWN, rssiSmoothings, rssiSmoothings, rssiSmoothing_read, rssiSmoothing_write}; + +bool Radio::dataMode_read() +{ + fsk.RegPktConfig2.word = radio.read_u16(REG_FSK_PACKETCONFIG2); + return fsk.RegPktConfig2.bits.DataModePacket; +} + +bool Radio::dataMode_push() +{ + fsk.RegPktConfig2.bits.DataModePacket ^= 1; + radio.write_u16(REG_FSK_PACKETCONFIG2, fsk.RegPktConfig2.word); + return fsk.RegPktConfig2.bits.DataModePacket; +} + +const toggle_item_t Radio::dataMode_item = { _ITEM_TOGGLE, + "continuous", + "packet ", + dataMode_read, dataMode_push +}; + +bool Radio::bitSyncOn_read(void) +{ + fsk.RegOokPeak.octet = radio.read_reg(REG_FSK_OOKPEAK); + return fsk.RegOokPeak.bits.BitSyncOn; +} + +bool Radio::bitSyncOn_push(void) +{ + fsk.RegOokPeak.bits.BitSyncOn ^= 1; + radio.write_reg(REG_FSK_OOKPEAK, fsk.RegOokPeak.octet); + return fsk.RegOokPeak.bits.BitSyncOn; +} + +const toggle_item_t Radio::bitSyncOn_item = { _ITEM_TOGGLE, + "BitSyncOn", NULL, + bitSyncOn_read, bitSyncOn_push +}; + +const button_item_t Radio::pdLabel_item = { _ITEM_BUTTON, "PreambleDetector", NULL}; + +bool Radio::pdOn_read(void) +{ + fsk.RegPreambleDetect.octet = radio.read_reg(REG_FSK_PREAMBLEDETECT); + return fsk.RegPreambleDetect.bits.PreambleDetectorOn; +} + +bool Radio::pdOn_push(void) +{ + fsk.RegPreambleDetect.bits.PreambleDetectorOn ^= 1; + radio.write_reg(REG_FSK_PREAMBLEDETECT, fsk.RegPreambleDetect.octet); + return fsk.RegPreambleDetect.bits.PreambleDetectorOn; +} + +const toggle_item_t Radio::pdOn_item = { _ITEM_TOGGLE, + "On", NULL, + pdOn_read, pdOn_push +}; + +const char* const pdsizes[] = { + "1 byte ", // 0 + "2 bytes", // 1 + "3 bytes", // 2 + NULL +}; + +unsigned Radio::pdSize_read(bool) +{ + fsk.RegPreambleDetect.octet = radio.read_reg(REG_FSK_PREAMBLEDETECT); + return fsk.RegPreambleDetect.bits.PreambleDetectorSize; +} + +menuMode_e Radio::pdSize_write(unsigned sidx) +{ + fsk.RegPreambleDetect.bits.PreambleDetectorSize = sidx; + radio.write_reg(REG_FSK_PREAMBLEDETECT, fsk.RegPreambleDetect.octet); + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::pdSize_item = { _ITEM_DROPDOWN, pdsizes, pdsizes, pdSize_read, pdSize_write}; + +void Radio::pdTol_print(void) +{ + fsk.RegPreambleDetect.octet = radio.read_reg(REG_FSK_PREAMBLEDETECT); + pc.printf("%u", fsk.RegPreambleDetect.bits.PreambleDetectorTol); +} + +bool Radio::pdTol_write(const char* txt) +{ + unsigned n; + sscanf(txt, "%u", &n); + fsk.RegPreambleDetect.bits.PreambleDetectorTol = n; + radio.write_reg(REG_FSK_PREAMBLEDETECT, fsk.RegPreambleDetect.octet); + return false; +} + +const value_item_t Radio::pdTol_item = { _ITEM_VALUE, 3, pdTol_print, pdTol_write}; + +bool Radio::TxStartCondition_read() +{ + fsk.RegFifoThreshold.octet = radio.read_reg(REG_FSK_FIFOTHRESH); + return fsk.RegFifoThreshold.bits.TxStartCondition; +} + +bool Radio::TxStartCondition_push() +{ + fsk.RegFifoThreshold.bits.TxStartCondition ^= 1; + radio.write_reg(REG_FSK_FIFOTHRESH, fsk.RegFifoThreshold.octet); + return fsk.RegFifoThreshold.bits.TxStartCondition; +} + +const toggle_item_t Radio::TxStartCondition_item = { _ITEM_TOGGLE, + "FifoLevel ", // 0 + "FifoNotEmpty", // 1 + TxStartCondition_read, TxStartCondition_push +}; + +void Radio::FifoThreshold_print(void) +{ + fsk.RegFifoThreshold.octet = radio.read_reg(REG_FSK_FIFOTHRESH); + pc.printf("%u", fsk.RegFifoThreshold.bits.FifoThreshold); +} + +bool Radio::FifoThreshold_write(const char* txt) +{ + unsigned n; + sscanf(txt, "%u", &n); + fsk.RegFifoThreshold.bits.FifoThreshold = n; + radio.write_reg(REG_FSK_FIFOTHRESH, fsk.RegFifoThreshold.octet); + return false; +} + +const value_item_t Radio::FifoThreshold_item = { _ITEM_VALUE, 3, FifoThreshold_print, FifoThreshold_write}; + +const char* const dcFrees[] = { + "none ", // 0 + "manchester", // 1 + "whitening ", // 2 + NULL +}; + +unsigned Radio::dcFree_read(bool fw) +{ + fsk.RegPktConfig1.octet = radio.read_reg(REG_FSK_PACKETCONFIG1); + return fsk.RegPktConfig1.bits.DcFree; +} + +menuMode_e Radio::dcFree_write(unsigned sidx) +{ + fsk.RegPktConfig1.bits.DcFree = sidx; + radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet); + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::dcFree_item = { _ITEM_DROPDOWN, dcFrees, dcFrees, dcFree_read, dcFree_write}; + +bool Radio::fskook_crcon_read() +{ + fsk.RegPktConfig1.octet = radio.read_reg(REG_FSK_PACKETCONFIG1); + return fsk.RegPktConfig1.bits.CrcOn; +} + +bool Radio::fskook_crcon_push() +{ + fsk.RegPktConfig1.bits.CrcOn ^= 1; + radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet); + + if (radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER) + fsk.config_dio0_for_pktmode_rx(); + + return fsk.RegPktConfig1.bits.CrcOn; +} + +const toggle_item_t Radio::fskook_crcon_item = { _ITEM_TOGGLE, + "CrcOn", NULL, + fskook_crcon_read, fskook_crcon_push +}; + +void Radio::rssiThresh_print() +{ + fsk.RegRssiThresh = radio.read_reg(REG_FSK_RSSITHRESH); + pc.printf("%.1f", fsk.RegRssiThresh / -2.0); +} + +bool Radio::rssiThresh_write(const char* txt) +{ + float dbm; + sscanf(txt, "%f", &dbm); + fsk.RegRssiThresh = dbm * -2.0; + radio.write_reg(REG_FSK_RSSITHRESH, fsk.RegRssiThresh); + return false; +} + +const value_item_t Radio::rssiThresh_item = { _ITEM_VALUE, 3, rssiThresh_print, rssiThresh_write}; + +bool Radio::pblPol_read() +{ + fsk.RegSyncConfig.octet = radio.read_reg(REG_FSK_SYNCCONFIG); + return fsk.RegSyncConfig.bits.PreamblePolarity; +} + +bool Radio::pblPol_push() +{ + fsk.RegSyncConfig.bits.PreamblePolarity ^= 1; + radio.write_reg(REG_FSK_SYNCCONFIG, fsk.RegSyncConfig.octet); + return fsk.RegSyncConfig.bits.PreamblePolarity; +} + +const toggle_item_t Radio::pblPol_item = { _ITEM_TOGGLE, + "0xaa", + "0x55", + pblPol_read, pblPol_push +}; + +const menu_t Radio::fsk_menu[] = { + { {FIRST_CHIP_MENU_ROW, 22}, "bps:", &fsk_ook_bitrate_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW, 34}, "fdev:", &gfsk_fdev_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW, 47}, "BT:", &gfsk_bt_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW, 57}, "length:", &fskook_pktfmt_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+1, 1}, "rxbw:", &rxbw_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 14}, "afcbw:", &afcbw_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 27}, "preambleLen:", &pblLen_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 47}, "RxTrigger:", &rxTrigger_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 72}, NULL, &pblPol_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+2, 1}, "syncWord:", &syncWord_item, FLAG_MSGTYPE_ALL, &syncSize_item}, + { {FIRST_CHIP_MENU_ROW+2, 27}, "syncSize:", &syncSize_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+2, 39}, NULL, &syncOn_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+2, 47}, "DataMode:", &dataMode_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+2, 69}, NULL, &bitSyncOn_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+3, 1}, NULL, &pdLabel_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+3, 18}, NULL, &pdOn_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+3, 23}, "size:", &pdSize_item , FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+3, 36}, "tol:", &pdTol_item , FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+3, 48}, "rssiThresh:", &rssiThresh_item , FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+4, 1}, NULL, &agcautoon_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+4, 11}, NULL, &afcautoon_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+4, 22}, NULL, &RestartRxOnCollision_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+4, 43}, NULL, &RestartRxWithPllLock_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+4, 64}, NULL, &RestartRxWithoutPllLock_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+5, 1}, NULL, &AfcAutoClearOn_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+5, 17}, NULL, &AgcStart_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+5, 27}, NULL, &AfcClear_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+5, 37}, "rssiOffset:", &rssiOffset_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+5, 52}, "rssiSmoothing:", &rssiSmoothing_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+6, 1}, "TxStartCondition:", &TxStartCondition_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+6, 32}, "FifoThreshold:", &FifoThreshold_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+6, 50}, "dcFree:", &dcFree_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+6, 68}, NULL, &fskook_crcon_item, FLAG_MSGTYPE_ALL }, + + { {0, 0}, NULL, NULL } +}; + +const button_item_t Radio::ookLabel_item = { _ITEM_BUTTON, "Ook", NULL}; + +const menu_t Radio::common_menu[] = { + { {FIRST_CHIP_MENU_ROW, 1}, NULL, &paSelect_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW, 10}, "ocp mA:", &ocp_item, FLAG_MSGTYPE_ALL }, + { {0, 0}, NULL, NULL } +}; + +const char* const ook_peak_steps[] = { + "0.5", // 0 + "1.0", // 1 + "1.5", // 2 + "2.0", // 3 + "3.0", // 4 + "4.0", // 5 + "5.0", // 6 + "6.0", // 7 + NULL +}; + +unsigned Radio::ook_peak_step_read(bool fw) +{ + fsk.RegOokPeak.octet = radio.read_reg(REG_FSK_OOKPEAK); + return fsk.RegOokPeak.bits.OokPeakThreshStep; +} + +menuMode_e Radio::ook_peak_step_write(unsigned sidx) +{ + fsk.RegOokPeak.bits.OokPeakThreshStep = sidx; + radio.write_reg(REG_FSK_OOKPEAK, fsk.RegOokPeak.octet); + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::ook_peak_step_item = { _ITEM_DROPDOWN, ook_peak_steps, ook_peak_steps, ook_peak_step_read, ook_peak_step_write}; + +const char* const ook_peak_decs[] = { + "once per chip ", // 0 + "once every 2 chips ", // 1 + "once every 4 chips ", // 2 + "once every 8 chips ", // 3 + "twice in each chip ", // 4 + "4 times in each chip ", // 5 + "8 times in each chip ", // 6 + "16 times in each chip", // 7 + NULL +}; + +unsigned Radio::ook_peak_dec_read(bool fw) +{ + RegOokAvg_t RegOokAvg; + RegOokAvg.octet = radio.read_reg(REG_FSK_OOKAVG); + return RegOokAvg.bits.OokPeakThreshDec; +} + +menuMode_e Radio::ook_peak_dec_write(unsigned sidx) +{ + RegOokAvg_t RegOokAvg; + RegOokAvg.octet = radio.read_reg(REG_FSK_OOKAVG); + RegOokAvg.bits.OokPeakThreshDec = sidx; + radio.write_reg(REG_FSK_OOKAVG, RegOokAvg.octet); + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::ook_peak_dec_item = { _ITEM_DROPDOWN, ook_peak_decs, ook_peak_decs, ook_peak_dec_read, ook_peak_dec_write}; + +void Radio::ookFixedThresh_print() +{ + pc.printf("%u", radio.read_reg(REG_FSK_OOKFIX)); +} + +bool Radio::ookFixedThresh_write(const char* txt) +{ + unsigned n; + sscanf(txt, "%u", &n); + radio.write_reg(REG_FSK_OOKFIX, n); + return false; +} + +const value_item_t Radio::ookFixedThresh_item = { _ITEM_VALUE, 3, ookFixedThresh_print, ookFixedThresh_write}; + +const char* const ook_avgOffsets[] = { + "0.0dB", // 0 + "2.0dB", // 1 + "4.0dB", // 2 + "6.0dB", // 3 + NULL +}; + +unsigned Radio::ook_avgOffset_read(bool fw) +{ + RegOokAvg_t RegOokAvg; + RegOokAvg.octet = radio.read_reg(REG_FSK_OOKAVG); + return RegOokAvg.bits.OokAverageOffset; +} + +menuMode_e Radio::ook_avgOffset_write(unsigned sidx) +{ + RegOokAvg_t RegOokAvg; + RegOokAvg.octet = radio.read_reg(REG_FSK_OOKAVG); + RegOokAvg.bits.OokAverageOffset = sidx; + radio.write_reg(REG_FSK_OOKAVG, RegOokAvg.octet); + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::ook_avgOffset_item = { _ITEM_DROPDOWN, ook_avgOffsets, ook_avgOffsets, ook_avgOffset_read, ook_avgOffset_write}; + +const char* const ook_avgFilters[] = { + "chip rate / 32.π", // 0 + "chip rate / 8.π ", // 1 + "chip rate / 4.π ", // 2 + "chip rate / 2.π ", // 3 + NULL +}; + +unsigned Radio::ook_avgFilter_read(bool fw) +{ + RegOokAvg_t RegOokAvg; + RegOokAvg.octet = radio.read_reg(REG_FSK_OOKAVG); + return RegOokAvg.bits.OokAverageThreshFilt; +} + +menuMode_e Radio::ook_avgFilter_write(unsigned sidx) +{ + RegOokAvg_t RegOokAvg; + RegOokAvg.octet = radio.read_reg(REG_FSK_OOKAVG); + RegOokAvg.bits.OokAverageThreshFilt = sidx; + radio.write_reg(REG_FSK_OOKAVG, RegOokAvg.octet); + return MENUMODE_REDRAW; +} + +const dropdown_item_t Radio::ook_avgFilter_item = { _ITEM_DROPDOWN, ook_avgFilters, ook_avgFilters, ook_avgFilter_read, ook_avgFilter_write}; + +const char* const ookthreshs[] = { + "fixed ", // 0 + "peak ", // 1 + "average", // 2 + NULL +}; + + +unsigned Radio::ookthreshtype_read(bool) +{ + fsk.RegOokPeak.octet = radio.read_reg(REG_FSK_OOKPEAK); + + return fsk.RegOokPeak.bits.OokThreshType; +} + +menuMode_e Radio::ookthreshtype_write(unsigned sidx) +{ + fsk.RegOokPeak.bits.OokThreshType = sidx; + radio.write_reg(REG_FSK_OOKPEAK, fsk.RegOokPeak.octet); + + return MENUMODE_REINIT_MENU; +} + +const dropdown_item_t Radio::ookthreshtype_item = { _ITEM_DROPDOWN, ookthreshs, ookthreshs, ookthreshtype_read, ookthreshtype_write}; + +const menu_t Radio::ook_menu[] = { + { {FIRST_CHIP_MENU_ROW, 22}, "bps:", &fsk_ook_bitrate_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW, 34}, "Fcutoff=", &ook_bt_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW, 56}, "length:", &fskook_pktfmt_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+1, 1}, "rxbw:", &rxbw_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 12}, "afcbw:", &afcbw_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 25}, "preambleLen:", &pblLen_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+1, 47}, "RxTrigger:", &rxTrigger_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+2, 1}, "syncWord:", &syncWord_item, FLAG_MSGTYPE_ALL, &syncSize_item}, + { {FIRST_CHIP_MENU_ROW+2, 27}, "syncSize:", &syncSize_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+2, 39}, NULL, &syncOn_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+2, 47}, "DataMode:", &dataMode_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+2, 69}, NULL, &bitSyncOn_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+3, 1}, NULL, &pdLabel_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+3, 18}, NULL, &pdOn_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+3, 23}, "size:", &pdSize_item , FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+3, 36}, "tol:", &pdTol_item , FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+3, 48}, "rssiThresh:", &rssiThresh_item , FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+4, 1}, "TxStartCondition:", &TxStartCondition_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+4, 32}, "FifoThreshold:", &FifoThreshold_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+4, 50}, "dcFree:", &dcFree_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+4, 68}, NULL, &fskook_crcon_item, FLAG_MSGTYPE_ALL }, + + { {FIRST_CHIP_MENU_ROW+5, 1}, NULL, &ookLabel_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+5, 5}, "threshType:", &ookthreshtype_item, FLAG_MSGTYPE_ALL }, + + { {0, 0}, NULL, NULL } +}; + +const menu_t Radio::ook_fixed_menu[] = { + { {FIRST_CHIP_MENU_ROW+5, 25}, "threshold:", &ookFixedThresh_item, FLAG_MSGTYPE_ALL }, + { {0, 0}, NULL, NULL } +}; + +const menu_t Radio::ook_peak_menu[] = { + { {FIRST_CHIP_MENU_ROW+5, 25}, "step:", &ook_peak_step_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+5, 40}, "dec:", &ook_peak_dec_item, FLAG_MSGTYPE_ALL }, + { {0, 0}, NULL, NULL } +}; + +const menu_t Radio::ook_average_menu[] = { + { {FIRST_CHIP_MENU_ROW+5, 25}, "offset:", &ook_avgOffset_item, FLAG_MSGTYPE_ALL }, + { {FIRST_CHIP_MENU_ROW+5, 45}, "filter:", &ook_avgFilter_item, FLAG_MSGTYPE_ALL }, + { {0, 0}, NULL, NULL } +}; + +void Radio::boardInit(const RadioEvents_t* e) +{ + targetInit(); + + RadioEvents = e; + + RegPaRamp.octet = radio.read_reg(REG_PARAMP); + + if (radio.type == SX1276) { + lora_bw_item.printed_strs = lora_bws_1276; + lora_bw_item.selectable_strs = lora_bws_1276; + } else if (radio.type == SX1272) { + lora_bw_item.printed_strs = lora_bws_1272; + lora_bw_item.selectable_strs = lora_bws_1272; + } + + lpt.start(); +} + +unsigned Radio::read_register(unsigned addr) +{ + return radio.read_reg(addr); +} + +void Radio::write_register(unsigned addr, unsigned val) +{ + radio.write_reg(addr, val); +} + +void Radio::test() { } + +#endif /* ..SX127x_H */ +