Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: LoRaWAN-SanJose_Bootcamp LoRaWAN-grove-cayenne LoRaWAN-classC-demo LoRaWAN-grove-cayenne ... more
Diff: radio/radio_sx127x.cpp
- Revision:
- 8:5a5ea7cc946f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/radio_sx127x.cpp Wed May 23 10:20:07 2018 -0700 @@ -0,0 +1,453 @@ +#include "radio.h" +#ifdef SX127x_H +#include "board.h" + +LowPowerTimer Radio::lpt; + +void Radio::Sleep() +{ + radio.set_opmode(RF_OPMODE_SLEEP); +} + +void Radio::Standby() +{ + radio.set_opmode(RF_OPMODE_STANDBY); +} + +bool Radio::CheckRfFrequency(unsigned hz) +{ + return true; +} + +void Radio::SetChannel(unsigned hz) +{ + radio.set_frf_MHz(hz / 1000000.0); + MAC_PRINTF(" %uhz ", hz); +} + +LowPowerTimeout TxTimeoutEvent; + +void SX1272OnTimeoutIrq( void ) +{ + Radio::radio.set_opmode(RF_OPMODE_STANDBY); +} + +void Radio::SetTxContinuousWave(unsigned hz, int8_t dbm, unsigned timeout_us) +{ + Radio::SetChannel(hz); + /* TODO: fsk enable, set regPacketConfig2.datamode */ + set_tx_dbm(dbm); + TxTimeoutEvent.attach_us(SX1272OnTimeoutIrq, timeout_us); + radio.set_opmode(RF_OPMODE_TRANSMITTER); +} + +#define LORA_MAC_PRIVATE_SYNCWORD 0x12 +#define LORA_MAC_PUBLIC_SYNCWORD 0x34 +void Radio::SetPublicNetwork(bool en) +{ + radio.write_reg(REG_LR_SYNC_BYTE, en ? LORA_MAC_PUBLIC_SYNCWORD : LORA_MAC_PRIVATE_SYNCWORD); +} + +uint32_t Radio::Random(void) +{ + uint32_t ret = 0; + unsigned i; + + radio.set_opmode(RF_OPMODE_RECEIVER); + for (i = 0; i < 32; i++) { + uint32_t r; + wait_us(3000); + r = radio.read_reg(REG_LR_WIDEBAND_RSSI); + r <<= ((i & 7) << 2); + ret ^= r; + } + + return ret; +} + +void Radio::LoRaConfig(uint32_t bandwidth, uint8_t datarate, uint8_t coderate, uint16_t preambleLen, bool fixLen, bool crcOn) +{ + float sp; + + if (!radio.RegOpMode.bits.LongRangeMode) { + lora.enable(); + } + radio.write_reg(REG_LR_IRQFLAGSMASK, 0); + + MAC_PRINTF("sf%u bw%u ", datarate, bandwidth); + lora.RegModemConfig2.sx1276bits.SpreadingFactor = datarate; + if (radio.type == SX1276) { + MAC_PRINTF("sx1276 "); + lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn = crcOn; + lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn = fixLen; + lora.RegModemConfig.sx1276bits.CodingRate = coderate; + lora.RegModemConfig.sx1276bits.Bw = bandwidth + 7; + lora.RegModemConfig3.octet = radio.read_reg(REG_LR_MODEMCONFIG3); + sp = lora.get_symbol_period(); + if (sp > 16) + lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 1; + else + lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 0; + radio.write_reg(REG_LR_MODEMCONFIG3, lora.RegModemConfig3.octet); + } else if (radio.type == SX1272) { + lora.RegModemConfig.sx1272bits.RxPayloadCrcOn = crcOn; + lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn = fixLen; + lora.RegModemConfig.sx1272bits.CodingRate = coderate; + lora.RegModemConfig.sx1272bits.Bw = bandwidth; + if (lora.get_symbol_period() > 16) + lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 1; + else + lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 0; + MAC_PRINTF("sx1272 "); + } else { + MAC_PRINTF("\e[31msx127?\e[0m "); + return; + } + + //printf(" {%02x %02x} ", lora.RegModemConfig.octet, lora.RegModemConfig2.octet); + radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet); + radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet); + + lora.RegPreamble = preambleLen; + radio.write_u16(REG_LR_PREAMBLEMSB, lora.RegPreamble); +} + +void Radio::SetRxConfig( + RadioModems_t modem, + uint32_t bandwidth, + uint32_t datarate, + uint8_t coderate, + uint32_t bandwidthAfc, + uint16_t preambleLen, + uint16_t symbTimeout, + bool fixLen, + uint8_t payloadLen, + bool crcOn, + bool iqInverted) +{ + if (modem == MODEM_FSK) { + if (radio.RegOpMode.bits.LongRangeMode) + fsk.enable(false); + /* TODO */ + //uint32_t bandwidthAfc, + } else if (modem == MODEM_LORA) { + uint16_t reg_u16; + + LoRaConfig(bandwidth, datarate, coderate, preambleLen, fixLen, crcOn); + + reg_u16 = radio.read_u16(REG_LR_MODEMCONFIG2); + reg_u16 &= 0xfc00; + reg_u16 |= symbTimeout; + radio.write_u16(REG_LR_MODEMCONFIG2, reg_u16); + //MAC_PRINTF("rxconf symbt %02x %02x mask:%02x\r\n", radio.read_reg(REG_LR_MODEMCONFIG2), radio.read_reg(REG_LR_MODEMCONFIG2+1), radio.read_reg(REG_LR_IRQFLAGSMASK)); + + lora.invert_rx(iqInverted); + } +} + +void Radio::SetTxConfig( + RadioModems_t modem, + int8_t dbm, + uint32_t fdev, + uint32_t bandwidth, + uint32_t datarate, + uint8_t coderate, + uint16_t preambleLen, + bool fixLen, + bool crcOn, + bool iqInverted) +{ + set_tx_dbm(dbm); + + if (modem == MODEM_FSK) { + if (radio.RegOpMode.bits.LongRangeMode) + fsk.enable(false); + /* TODO */ + } else if (modem == MODEM_LORA) { + LoRaConfig(bandwidth, datarate, coderate, preambleLen, fixLen, crcOn); + + lora.invert_tx(iqInverted); + } +} + +void Radio::SetRxMaxPayloadLength(RadioModems_t modem, uint8_t max) +{ + /* TODO fsk */ + radio.write_reg(REG_LR_RX_MAX_PAYLOADLENGTH, max); +} + +const RadioEvents_t* RadioEvents; + + +#if 0 +void dumpregs() +{ + unsigned i; + //MAC_PRINTF("%02x) %02x\r\n", i, radio.read_reg(i)); + for (i = 0; i < 0x70; i++) { + MAC_PRINTF("%02x) %02x\r\n", i, radio.read_reg(i)); + } +} +#endif /* if 0 */ + +volatile struct pe { + uint8_t dio0 : 1; + uint8_t dio1 : 1; + uint8_t txing : 1; +} pinEvent; +volatile us_timestamp_t dio0at; + +void +Radio::dio0UserContext() +{ + if (!pinEvent.txing) { + lora.service(); + if (!lora.RegIrqFlags.bits.RxDone) { + MAC_PRINTF("not-rxdone\r\n"); + } else if (RadioEvents->RxDone) { + int8_t rssi; + float snr = lora.RegPktSnrValue / 4.0; + + rssi = lora.get_pkt_rssi(); + if (snr < 0) + rssi += snr; + //MAC_PRINTF("rxdone snr:%.2f, rssi:%d\r\n", snr, rssi); + RadioEvents->RxDone(radio.rx_buf, lora.RegRxNbBytes, rssi, snr, dio0at); + } + } +} + +void Radio::dio0isr() +{ + dio0at = lpt.read_us(); + + if (pinEvent.txing) { + /* TxDone handling requires low latency */ + if (RadioEvents->TxDone) + RadioEvents->TxDone(dio0at); + + lora.service(); + pinEvent.txing = 0; + } else + pinEvent.dio0 = 1; +} + +void Radio::dio1UserContext() +{ + lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS); + + MAC_PRINTF("\e[7mdio1:%02x\e[0m\r\n", lora.RegIrqFlags.octet); + + if (RadioEvents->RxTimeout) + RadioEvents->RxTimeout(); + + radio.write_reg(REG_LR_IRQFLAGS, 0x80); // ensure RxTimeout is cleared +} + +void Radio::dio1isr() +{ + pinEvent.dio1 = 1; +} + +void Radio::Init(const RadioEvents_t* e) +{ + dio0.rise(dio0isr); + dio1.rise(dio1isr); + + radio.rf_switch = rfsw_callback; + boardInit(); + + RadioEvents = e; + lpt.start(); +} + +int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh) +{ + if (radio.RegOpMode.bits.Mode == RF_OPMODE_SLEEP) { + radio.set_opmode(RF_OPMODE_STANDBY); + wait_us(1000); + } + radio.write_reg(REG_LR_IRQFLAGS, 0x08); // ensure TxDone is cleared + MAC_PRINTF("Radio::Send() dio:%u:%u opmode:%02x ", radio.dio0.read(), radio.dio1.read(), radio.read_reg(REG_OPMODE)); + lora.RegPayloadLength = size; + radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength); + + if (maxListenTime > 0) { + int rssi; + us_timestamp_t startAt, chFreeAt, now; + lora.start_rx(RF_OPMODE_RECEIVER); + startAt = lpt.read_us(); +Lstart: + do { + now = lpt.read_us(); + if ((now - startAt) > maxListenTime) { + return -1; + } + rssi = lora.get_current_rssi(); + } while (rssi > rssiThresh); + chFreeAt = lpt.read_us(); + do { + now = lpt.read_us(); + rssi = lora.get_current_rssi(); + if (rssi > rssiThresh) { + goto Lstart; + } + } while ((now - chFreeAt) < channelFreeTime); + } + + lora.start_tx(size); + pinEvent.txing = 1; + + return 0; +} + +void Radio::Rx(unsigned timeout) +{ + if (timeout == 0) { + lora.start_rx(RF_OPMODE_RECEIVER); + MAC_PRINTF("startRxC "); + } else { + lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS); // yyy tmp remove + lora.start_rx(RF_OPMODE_RECEIVER_SINGLE); + MAC_PRINTF("startRxS:%02x ", lora.RegIrqFlags.octet); + } + + pinEvent.txing = 0; + +} + + +void Radio::ocp(uint8_t ma) +{ + if (ma < 130) + radio.RegOcp.bits.OcpTrim = (ma - 45) / 5; + else + radio.RegOcp.bits.OcpTrim = (ma + 30) / 10; + radio.write_reg(REG_OCP, radio.RegOcp.octet); + + radio.RegOcp.octet = radio.read_reg(REG_OCP); + if (radio.RegOcp.bits.OcpTrim < 16) + ma = 45 + (5 * radio.RegOcp.bits.OcpTrim); + else if (radio.RegOcp.bits.OcpTrim < 28) + ma = (10 * radio.RegOcp.bits.OcpTrim) - 30; + else + ma = 240; + //MAC_PRINTF("Ocp: %dmA\r\n", ma); +} + + +void Radio::PrintStatus() +{ +#ifdef MAC_DEBUG + radio.RegOpMode.octet = radio.read_reg(REG_OPMODE); + switch (radio.RegOpMode.bits.Mode) { + case RF_OPMODE_SLEEP: MAC_PRINTF("SLEEP "); break; + case RF_OPMODE_STANDBY: MAC_PRINTF("STBY "); break; + case RF_OPMODE_SYNTHESIZER_TX: MAC_PRINTF("FSTX "); break; + case RF_OPMODE_TRANSMITTER: MAC_PRINTF("TX "); break; + case RF_OPMODE_SYNTHESIZER_RX: MAC_PRINTF("FSRX "); break; + case RF_OPMODE_RECEIVER: MAC_PRINTF("RXC "); break; + case RF_OPMODE_RECEIVER_SINGLE: MAC_PRINTF("RXS "); break; + case RF_OPMODE_CAD: MAC_PRINTF("CAD "); break; + } + + MAC_PRINTF("dio:%u:%u opmode:%02x %.2fMHz sf%ubw%u ", radio.dio0.read(), radio.dio1.read(), radio.RegOpMode.octet, radio.get_frf_MHz(), lora.getSf(), lora.getBw()); + lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS); + MAC_PRINTF("irqFlags:%02x\r\n", lora.RegIrqFlags.octet); +#endif /* MAC_DEBUG */ +} + +#ifdef DUTY_ENABLE +us_timestamp_t +Radio::TimeOnAir(RadioModems_t m, uint8_t pktLen) +{ + uint32_t airTime = 0; + + switch (m) + { + case MODEM_FSK: + { + /* TODO + airTime = round( ( 8 * ( SX1272.Settings.Fsk.PreambleLen + + ( ( SX1272Read( REG_SYNCCONFIG ) & ~RF_SYNCCONFIG_SYNCSIZE_MASK ) + 1 ) + + ( ( SX1272.Settings.Fsk.FixLen == 0x01 ) ? 0.0 : 1.0 ) + + ( ( ( SX1272Read( REG_PACKETCONFIG1 ) & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK ) != 0x00 ) ? 1.0 : 0 ) + + pktLen + + ( ( SX1272.Settings.Fsk.CrcOn == 0x01 ) ? 2.0 : 0 ) ) / + SX1272.Settings.Fsk.Datarate ) * 1e3 ); + */ + } + break; + case MODEM_LORA: + { + double bw = 0.0; + uint8_t fixLen, bandwidth, LowDatarateOptimize, coderate, crcOn ; + if (radio.type == SX1276) { + coderate = lora.RegModemConfig.sx1276bits.CodingRate; + LowDatarateOptimize = lora.RegModemConfig3.sx1276bits.LowDataRateOptimize; + fixLen = lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn; + bandwidth = lora.RegModemConfig.sx1276bits.Bw - 7; + crcOn = lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn; + } else if (radio.type == SX1272) { + coderate = lora.RegModemConfig.sx1272bits.CodingRate; + LowDatarateOptimize = lora.RegModemConfig.sx1272bits.LowDataRateOptimize; + fixLen = lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn; + bandwidth = lora.RegModemConfig.sx1272bits.Bw; + crcOn = lora.RegModemConfig.sx1272bits.RxPayloadCrcOn; + } else + return 0; + + switch( bandwidth ) + { + case 0: // 125 kHz + bw = 125;//ms: 125e3; + break; + case 1: // 250 kHz + bw = 250;//ms:250e3; + break; + case 2: // 500 kHz + bw = 500;//ms:500e3; + break; + } + + // Symbol rate : time for one symbol (secs) + double rs = bw / ( 1 << lora.RegModemConfig2.sx1276bits.SpreadingFactor ); + double ts = 1 / rs; + // time of preamble + double tPreamble; + tPreamble = (lora.RegPreamble + 4.25 ) * ts; + // Symbol length of payload and time + double tmp = ceil( ( 8 * pktLen - 4 * lora.RegModemConfig2.sx1276bits.SpreadingFactor + + 28 + 16 * crcOn - + ( fixLen ? 20 : 0 ) ) / + ( double )( 4 * ( lora.RegModemConfig2.sx1276bits.SpreadingFactor - + ( ( LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) * + ( coderate + 4 ); + double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 ); + double tPayload = nPayload * ts; + // Time on air + double tOnAir = tPreamble + tPayload; + // return ms secs + airTime = floor( tOnAir * 1e3 + 0.999 ); + } + break; + } + return airTime; + +} +#endif /* DUTY_ENABLE */ + +void Radio::UserContext() +{ + if (pinEvent.dio0) { + dio0UserContext(); + pinEvent.dio0 = 0; + } + + if (pinEvent.dio1) { + dio1UserContext(); + pinEvent.dio1 = 0; + } +} +#endif /* ..SX127x_H */ +