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
radio/radio.cpp
- Committer:
- Wayne Roberts
- Date:
- 2018-05-04
- Revision:
- 7:4b6f960dcca2
- Parent:
- 4:e4bfe9183f94
File content as of revision 7:4b6f960dcca2:
#include "board.h" #include "radio.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; } }