1
Diff: radio_sx127x.cpp
- Revision:
- 0:9c052ff8dd6a
- Child:
- 1:e79b0a55135f
diff -r 000000000000 -r 9c052ff8dd6a radio_sx127x.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio_sx127x.cpp Thu Jul 05 17:31:54 2018 -0700 @@ -0,0 +1,481 @@ +#include "radio.h" +#ifdef SX127x_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); +} + +float Radio::getFrfMHz() +{ + return radio.get_frf_MHz(); +} + +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::LoRaPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn, bool invIQ) +{ + lora.RegPreamble = preambleLen; + radio.write_u16(REG_LR_PREAMBLEMSB, lora.RegPreamble); + + if (radio.type == SX1276) { + lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn = fixLen; + lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn = crcOn; + radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet); + } else if (radio.type == SX1272) { + lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn = fixLen; + lora.RegModemConfig.sx1272bits.RxPayloadCrcOn = crcOn; + } + + radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet); + + lora.invert_tx(invIQ); + lora.invert_rx(invIQ); +} + +void Radio::GFSKModemConfig(unsigned bps, unsigned bw_hz, unsigned fdev_hz) +{ + if (radio.RegOpMode.bits.LongRangeMode) + fsk.enable(false); + + fsk.set_bitrate(bps); + + fsk.set_rx_dcc_bw_hz(bw_hz, 0); + fsk.set_rx_dcc_bw_hz(bw_hz * 1.5, 1); + + fsk.set_tx_fdev_hz(fdev_hz); +} + + +void Radio::GFSKPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn) +{ + if (radio.RegOpMode.bits.LongRangeMode) + fsk.enable(false); + + radio.write_u16(REG_FSK_PREAMBLEMSB, preambleLen); + + fsk.RegPktConfig1.bits.PacketFormatVariable = fixLen ? 0 : 1; + fsk.RegPktConfig1.bits.CrcOn = crcOn; + radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet); +} + +void Radio::SetLoRaSymbolTimeout(uint8_t symbs) +{ + if (!radio.RegOpMode.bits.LongRangeMode) + lora.enable(); + + lora.RegModemConfig2.sx1272bits.SymbTimeoutMsb = 0; + radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet); + radio.write_reg(REG_LR_SYMBTIMEOUTLSB, symbs); +} + +void Radio::LoRaModemConfig(unsigned bwKHz, uint8_t sf, uint8_t coderate) +{ + float sp; + if (!radio.RegOpMode.bits.LongRangeMode) + lora.enable(); + + lora.RegModemConfig2.sx1276bits.SpreadingFactor = sf; + radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet); + + lora.setBw_KHz(bwKHz); + + if (radio.type == SX1276) { + lora.RegModemConfig.sx1276bits.CodingRate = coderate; + + 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.CodingRate = coderate; + + if (lora.get_symbol_period() > 16) + lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 1; + else + lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 0; + } + radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet); +} + +void Radio::SetRxMaxPayloadLength(RadioModems_t modem, uint8_t max) +{ + /* TODO fsk */ + radio.write_reg(REG_LR_RX_MAX_PAYLOADLENGTH, max); +} + +const RadioEvents_t* RadioEvents; + + +volatile struct pe { + uint8_t dio0 : 1; + uint8_t dio1 : 1; + uint8_t txing : 1; +} pinEvent; + +void +Radio::dio0UserContext() +{ + service_action_e act = lora.service(); + + if (!pinEvent.txing) { + if (act == SERVICE_READ_FIFO && RadioEvents->RxDone) { + int8_t rssi; + float snr = lora.RegPktSnrValue / 4.0; + + rssi = lora.get_pkt_rssi(); + if (snr < 0) + rssi += snr; + RadioEvents->RxDone(lora.RegRxNbBytes, rssi, snr); + } + } else if (act == SERVICE_TX_DONE) { + if (RadioEvents->TxDone_botHalf) + RadioEvents->TxDone_botHalf(); + } +} + +volatile us_timestamp_t Radio::irqAt; + +void Radio::dio0isr() +{ + irqAt = lpt.read_us(); + + if (pinEvent.txing) { + /* TxDone handling requires low latency */ + if (RadioEvents->TxDone_topHalf) + RadioEvents->TxDone_topHalf(); // TODO in callback read irqAt for timestamp of interrupt + + } + + pinEvent.dio0 = 1; +} + +void Radio::dio1UserContext() +{ + lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS); + + 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 + 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); + } else { + lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS); // yyy tmp remove + lora.start_rx(RF_OPMODE_RECEIVER_SINGLE); + } + + 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; +} + + +#if 0 +void Radio::PrintStatus() +{ +#ifdef MAC_DEBUG + radio.RegOpMode.octet = radio.read_reg(REG_OPMODE); + switch (radio.RegOpMode.bits.Mode) { + case RF_OPMODE_SLEEP: printf("SLEEP "); break; + case RF_OPMODE_STANDBY: printf("STBY "); break; + case RF_OPMODE_SYNTHESIZER_TX: printf("FSTX "); break; + case RF_OPMODE_TRANSMITTER: printf("TX "); break; + case RF_OPMODE_SYNTHESIZER_RX: printf("FSRX "); break; + case RF_OPMODE_RECEIVER: printf("RXC "); break; + case RF_OPMODE_RECEIVER_SINGLE: printf("RXS "); break; + case RF_OPMODE_CAD: printf("CAD "); break; + } + + 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); + printf("irqFlags:%02x\r\n", lora.RegIrqFlags.octet); +#endif /* MAC_DEBUG */ +} +#endif /* if 0 */ + +#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::service() +{ + if (pinEvent.dio0) { + dio0UserContext(); + pinEvent.txing = 0; + pinEvent.dio0 = 0; + } + + if (pinEvent.dio1) { + dio1UserContext(); + pinEvent.dio1 = 0; + } +} + +uint32_t Radio::lora_toa_us( uint8_t pktLen ) +{ + uint32_t airTime = 0; + uint8_t chipBW = Radio::lora.getBw(); + double bwKHz; + uint8_t LowDataRateOptimize; + bool FixLen; + uint8_t crcOn; + uint16_t preambleLen = Radio::radio.read_u16(REG_LR_PREAMBLEMSB); + + Radio::lora.RegModemConfig2.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG2); + Radio::lora.RegModemConfig.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG); + + if (Radio::radio.type == SX1276) { + chipBW -= 7; + Radio::lora.RegModemConfig3.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG3); + LowDataRateOptimize = Radio::lora.RegModemConfig3.sx1276bits.LowDataRateOptimize; + FixLen = Radio::lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn; + crcOn = Radio::lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn; + } else if (Radio::radio.type == SX1272) { + LowDataRateOptimize = Radio::lora.RegModemConfig.sx1272bits.LowDataRateOptimize; + FixLen = Radio::lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn; + crcOn = Radio::lora.RegModemConfig.sx1272bits.RxPayloadCrcOn; + } else + return 0; + + switch (chipBW) { + case 0: bwKHz = 125; break; + case 1: bwKHz = 250; break; + case 2: bwKHz = 500; break; + default: return 0; + } + + // Symbol rate : time for one symbol (secs) + double rs = bwKHz / ( 1 << Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor ); + double ts = 1 / rs; + // time of preamble + double tPreamble = ( preambleLen + 4.25 ) * ts; + // Symbol length of payload and time + double tmp = ceil( ( 8 * pktLen - 4 * Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor + + 28 + 16 * crcOn - + ( FixLen ? 20 : 0 ) ) / + ( double )( 4 * ( Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor - + ( ( LowDataRateOptimize > 0 ) ? 2 : 0 ) ) ) ) * + ( Radio::lora.getCodingRate(false) + 4 ); + double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 ); + double tPayload = nPayload * ts; + // Time on air + double tOnAir = tPreamble + tPayload; + // return microseconds + airTime = floor( tOnAir * 1000 + 0.999 ); + + return airTime; +} +#endif /* ..SX127x_H */ +