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_sx126x.cpp
- Committer:
- Wayne Roberts
- Date:
- 2018-05-23
- Revision:
- 8:5a5ea7cc946f
- Child:
- 9:fe8e08792ae9
File content as of revision 8:5a5ea7cc946f:
#include "radio.h" #ifdef SX126x_H #include "board.h" #include "SPIu.h" LowPowerTimer Radio::lpt; volatile us_timestamp_t dio1at; #ifdef TARGET_FF_ARDUINO SPIu spi(D11, D12, D13); // mosi, miso, sclk //spi, nss, busy, dio1 SX126x Radio::radio(spi, D7, D3, D5); DigitalOut antswPower(D8); AnalogIn xtalSel(A3); DigitalIn chipType(A2); #define CHIP_TYPE_SX1262 0 #define CHIP_TYPE_SX1261 1 #define PINNAME_NRST A0 #endif /* TARGET_FF_ARDUINO */ const RadioEvents_t* RadioEvents; PacketParams_t Radio::pp; RadioModems_t Radio::_m_; #ifdef TARGET_FF_MORPHO DigitalOut pc3(PC_3); // debug RX indication, for nucleo boards #endif /* TARGET_FF_MORPHO */ void Radio::Rx(unsigned timeout) { antswPower = 1; { uint8_t buf[8]; IrqFlags_t irqEnable; irqEnable.word = 0; irqEnable.bits.RxDone = 1; irqEnable.bits.Timeout = 1; buf[0] = irqEnable.word >> 8; // enable bits buf[1] = irqEnable.word; // enable bits buf[2] = irqEnable.word >> 8; // dio1 buf[3] = irqEnable.word; // dio1 buf[4] = 0; // dio2 buf[5] = 0; // dio2 buf[6] = 0; // dio3 buf[7] = 0; // dio3 radio.xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, buf); } #ifdef TARGET_FF_MORPHO pc3 = 1; #endif /* TARGET_FF_MORPHO */ if (timeout == 0) radio.start_rx(RX_TIMEOUT_CONTINUOUS); else radio.start_rx(timeout * RC_TICKS_PER_US); } void Radio::Standby() { radio.setStandby(STBY_RC); // STBY_XOSC antswPower = 0; } void Radio::Sleep() { radio.setSleep(true, false); antswPower = 0; } void Radio::SetTxContinuousWave(unsigned hz, int8_t dbm, unsigned timeout_us) { SetChannel(hz); radio.set_tx_dbm(chipType == CHIP_TYPE_SX1262, dbm); radio.xfer(OPCODE_SET_TX_CONTINUOUS, 0, NULL); } uint32_t Radio::Random(void) { uint32_t ret; radio.start_rx(RX_TIMEOUT_CONTINUOUS); ret = radio.readReg(REG_ADDR_RANDOM, 4); Standby(); return ret; } bool Radio::CheckRfFrequency(unsigned hz) { return true; } void Radio::SetChannel(unsigned hz) { radio.setMHz(hz / 1000000.0); } 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) { uint8_t buf[8]; if (modem == MODEM_FSK) buf[0] = PACKET_TYPE_GFSK; else buf[0] = PACKET_TYPE_LORA; radio.xfer(OPCODE_SET_PACKET_TYPE, 1, buf); buf[0] = 0; // TX base address buf[1] = 0; // RX base address radio.xfer(OPCODE_SET_BUFFER_BASE_ADDR, 2, buf); if (modem == MODEM_FSK) { FSKConfig(bandwidth, datarate, 0, preambleLen, fixLen, crcOn); pp.gfsk.PayloadLength = payloadLen; memcpy(buf, pp.buf, 8); radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, buf); } else if (modem == MODEM_LORA) { LoRaConfig(bandwidth, datarate, coderate, preambleLen, fixLen, crcOn, iqInverted); pp.lora.PayloadLength = payloadLen; memcpy(buf, pp.buf, 6); radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, buf); buf[0] = symbTimeout; radio.xfer(OPCODE_SET_LORA_SYMBOL_TIMEOUT, 1, buf); } { IrqFlags_t irqEnable; irqEnable.word = 0; irqEnable.bits.RxDone = 1; irqEnable.bits.Timeout = 1; buf[0] = irqEnable.word >> 8; // enable bits buf[1] = irqEnable.word; // enable bits buf[2] = irqEnable.word >> 8; // dio1 buf[3] = irqEnable.word; // dio1 buf[4] = 0; // dio2 buf[5] = 0; // dio2 buf[6] = 0; // dio3 buf[7] = 0; // dio3 radio.xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, buf); } } // ..SetRxConfig() void Radio::FSKConfig( uint32_t bandwidth, uint32_t datarate, uint32_t fdev, uint32_t preambleLen, bool fixLen, bool crcOn) { ModulationParams_t mp; uint32_t u32; u32 = 32 * (XTAL_FREQ / datarate); mp.gfsk.bitrateHi = datarate >> 16; // param1 mp.gfsk.bitrateMid = datarate >> 8; // param2 mp.gfsk.bitrateLo = datarate; // param3 mp.gfsk.PulseShape = GFSK_SHAPE_BT1_0; // param4 // param5: if (bandwidth < 5800) mp.gfsk.bandwith = GFSK_RX_BW_4800; else if (bandwidth < 7300) mp.gfsk.bandwith = GFSK_RX_BW_5800; else if (bandwidth < 9700) mp.gfsk.bandwith = GFSK_RX_BW_7300; else if (bandwidth < 11700) mp.gfsk.bandwith = GFSK_RX_BW_9700; else if (bandwidth < 14600) mp.gfsk.bandwith = GFSK_RX_BW_11700; else if (bandwidth < 19500) mp.gfsk.bandwith = GFSK_RX_BW_14600; else if (bandwidth < 23400) mp.gfsk.bandwith = GFSK_RX_BW_19500; else if (bandwidth < 29300) mp.gfsk.bandwith = GFSK_RX_BW_23400; else if (bandwidth < 39000) mp.gfsk.bandwith = GFSK_RX_BW_29300; else if (bandwidth < 46900) mp.gfsk.bandwith = GFSK_RX_BW_39000; else if (bandwidth < 58600) mp.gfsk.bandwith = GFSK_RX_BW_46900; else if (bandwidth < 78200) mp.gfsk.bandwith = GFSK_RX_BW_58600; else if (bandwidth < 93800) mp.gfsk.bandwith = GFSK_RX_BW_78200; else if (bandwidth < 117300) mp.gfsk.bandwith = GFSK_RX_BW_93800; else if (bandwidth < 156200) mp.gfsk.bandwith = GFSK_RX_BW_117300; else if (bandwidth < 187200) mp.gfsk.bandwith = GFSK_RX_BW_156200; else if (bandwidth < 234300) mp.gfsk.bandwith = GFSK_RX_BW_187200; else if (bandwidth < 312000) mp.gfsk.bandwith = GFSK_RX_BW_234300; else if (bandwidth < 373600) mp.gfsk.bandwith = GFSK_RX_BW_312000; else if (bandwidth < 467000) mp.gfsk.bandwith = GFSK_RX_BW_373600; else mp.gfsk.bandwith = GFSK_RX_BW_467000; if (fdev > 0) { u32 = fdev / FREQ_STEP; mp.gfsk.fdevHi = u32 >> 16; // param6 mp.gfsk.fdevMid = u32 >> 8; // param7 mp.gfsk.fdevLo = u32; // param8 } radio.xfer(OPCODE_SET_MODULATION_PARAMS, 8, mp.buf); pp.gfsk.PreambleLengthHi = preambleLen >> 8; pp.gfsk.PreambleLengthLo = preambleLen; pp.gfsk.PreambleDetectorLength = GFSK_PREAMBLE_DETECTOR_LENGTH_16BITS; pp.gfsk.SyncWordLength = 24; // 0xC194C1 pp.gfsk.AddrComp = 0; pp.gfsk.PacketType = fixLen; if (crcOn) pp.gfsk.CRCType = GFSK_CRC_2_BYTE; else pp.gfsk.CRCType = GFSK_CRC_OFF; } void Radio::LoRaConfig( uint32_t bandwidth, uint8_t datarate, uint8_t coderate, uint16_t preambleLen, bool fixLen, bool crcOn, bool iqInverted) { ModulationParams_t mp; float sp, khz; mp.lora.spreadingFactor = datarate; // param1 mp.lora.bandwidth = bandwidth + 4; // param2 mp.lora.codingRate = coderate; // param3 switch (mp.lora.bandwidth) { case LORA_BW_7: khz = 7.81; break; case LORA_BW_10: khz = 10.42; break; case LORA_BW_15: khz = 15.625; break; case LORA_BW_20: khz = 20.83; break; case LORA_BW_31: khz = 31.25; break; case LORA_BW_41: khz = 41.67; break; case LORA_BW_62: khz = 62.5; break; case LORA_BW_125: khz = 125; break; case LORA_BW_250: khz = 250; break; case LORA_BW_500: khz = 500; break; default: khz = 0; break; } sp = (1 << mp.lora.spreadingFactor) / khz; /* TCXO dependent */ if (sp > 16) mp.lora.LowDatarateOptimize = 1; // param4 else mp.lora.LowDatarateOptimize = 0; // param4 radio.xfer(OPCODE_SET_MODULATION_PARAMS, 4, mp.buf); pp.lora.PreambleLengthHi = preambleLen >> 8; pp.lora.PreambleLengthLo = preambleLen; pp.lora.HeaderType = fixLen; pp.lora.CRCType = crcOn; pp.lora.InvertIQ = 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) { uint8_t buf[8]; radio.set_tx_dbm(chipType == CHIP_TYPE_SX1262, dbm); if (modem == MODEM_FSK) buf[0] = PACKET_TYPE_GFSK; else buf[0] = PACKET_TYPE_LORA; radio.xfer(OPCODE_SET_PACKET_TYPE, 1, buf); buf[0] = 0; // TX base address buf[1] = 0; // RX base address radio.xfer(OPCODE_SET_BUFFER_BASE_ADDR, 2, buf); if (modem == MODEM_FSK) { FSKConfig(bandwidth, datarate, fdev, preambleLen, fixLen, crcOn); } else if (modem == MODEM_LORA) { LoRaConfig(bandwidth, datarate, coderate, preambleLen, fixLen, crcOn, iqInverted); } { IrqFlags_t irqEnable; irqEnable.word = 0; irqEnable.bits.TxDone = 1; irqEnable.bits.Timeout = 1; buf[0] = irqEnable.word >> 8; // enable bits buf[1] = irqEnable.word; // enable bits buf[2] = irqEnable.word >> 8; // dio1 buf[3] = irqEnable.word; // dio1 buf[4] = 0; // dio2 buf[5] = 0; // dio2 buf[6] = 0; // dio3 buf[7] = 0; // dio3 radio.xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, buf); } _m_ = modem; /* SetPacketParams written at Send() where payloadLength provided */ antswPower = 1; } // ..SetTxConfig() int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh) { uint8_t buf[8]; if (_m_ == MODEM_FSK) { pp.gfsk.PayloadLength = size; memcpy(buf, pp.buf, 8); radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, buf); } else if (_m_ == MODEM_LORA) { pp.lora.PayloadLength = size; memcpy(buf, pp.buf, 6); radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, buf); } if (maxListenTime > 0) { int rssi; us_timestamp_t startAt, chFreeAt, now; radio.start_rx(RX_TIMEOUT_CONTINUOUS); startAt = lpt.read_us(); Lstart: do { now = lpt.read_us(); if ((now - startAt) > maxListenTime) { return -1; } radio.xfer(OPCODE_GET_RSSIINST, 2, buf); rssi = buf[1] / -2; } while (rssi > rssiThresh); chFreeAt = lpt.read_us(); do { now = lpt.read_us(); radio.xfer(OPCODE_GET_RSSIINST, 2, buf); rssi = buf[1] / -2; if (rssi > rssiThresh) { goto Lstart; } } while ((now - chFreeAt) < channelFreeTime); } radio.start_tx(size); return 0; } // ..Send() void Radio::SetRxMaxPayloadLength(RadioModems_t modem, uint8_t max) { uint8_t buf[8]; if (modem == MODEM_FSK) { pp.gfsk.PayloadLength = max; memcpy(buf, pp.buf, 8); radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, buf); } else if (modem == MODEM_LORA) { pp.lora.PayloadLength = max; memcpy(buf, pp.buf, 6); radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, buf); } } void Radio::dio1_top_half() { dio1at = lpt.read_us(); if (radio.chipMode == CHIPMODE_TX) { /* TxDone handling requires low latency */ if (RadioEvents->TxDone) { RadioEvents->TxDone(dio1at); } } #ifdef TARGET_FF_MORPHO else pc3 = 0; #endif /* TARGET_FF_MORPHO */ } void Radio::timeout_callback(bool tx) { if (!tx) { if (RadioEvents->RxTimeout) RadioEvents->RxTimeout(); #ifdef TARGET_FF_MORPHO pc3 = 0; #endif /* TARGET_FF_MORPHO */ } // else TODO tx timeout } void Radio::rx_done(uint8_t size, float rssi, float snr) { RadioEvents->RxDone(radio.rx_buf, size, rssi, snr, dio1at); } void Radio::Init(const RadioEvents_t* e) { radio.txDone = NULL; radio.rxDone = rx_done; radio.timeout = timeout_callback; radio.dio1_topHalf = dio1_top_half; RadioEvents = e; lpt.start(); radio.SetDIO2AsRfSwitchCtrl(1); } void Radio::UserContext() { radio.service(); } void Radio::SetPublicNetwork(bool en) { uint16_t ppg; if (en) ppg = 0x3444; else ppg = 0x1424; radio.writeReg(REG_ADDR_LORA_SYNC, ppg, 2); } void Radio::PrintStatus() { uint8_t buf[4]; status_t status; IrqFlags_t irqFlags; radio.xfer(OPCODE_GET_IRQ_STATUS, 3, buf); irqFlags.word = buf[1] << 8; irqFlags.word |= buf[2]; printf("dio1:%u irqFlags:%04x\r\n", radio.getDIO1(), irqFlags.word); radio.xfer(OPCODE_GET_STATUS, 1, &status.octet); radio.PrintChipStatus(status); } #endif /* ..SX126x_H */