1
Diff: radio_sx126x.cpp
- Revision:
- 0:9c052ff8dd6a
- Child:
- 1:e79b0a55135f
diff -r 000000000000 -r 9c052ff8dd6a radio_sx126x.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio_sx126x.cpp Thu Jul 05 17:31:54 2018 -0700 @@ -0,0 +1,577 @@ +#include "radio.h" +#ifdef SX126x_H +#include "SPIu.h" + +extern RawSerial pc; + +LowPowerTimer Radio::lpt; +volatile us_timestamp_t Radio::irqAt; + +#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 + + #define LED_ON 1 + #define LED_OFF 0 + DigitalOut tx_led(A4); + DigitalOut rx_led(A5); + + void Radio::chipModeChange() + { + if (radio.chipMode == CHIPMODE_NONE) { + tx_led = LED_OFF; + rx_led = LED_OFF; + } else if (radio.chipMode == CHIPMODE_TX) { + tx_led = LED_ON; + rx_led = LED_OFF; + } else if (radio.chipMode == CHIPMODE_RX) { + tx_led = LED_OFF; + rx_led = LED_ON; + } + } +#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, 0, 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); + + //pc.printf("start_rx %u busy%u\r\n", timeout, busy.read()); +} + +void Radio::Standby() +{ + radio.setStandby(STBY_RC); // STBY_XOSC + + antswPower = 0; +} + +void Radio::Sleep() +{ + radio.setSleep(true, false); + + antswPower = 0; +} + +void Radio::set_tx_dbm(int8_t dbm) +{ + radio.set_tx_dbm(chipType == CHIP_TYPE_SX1262, dbm); +} + +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, 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); +} + +float Radio::getFrfMHz() +{ + return radio.getMHz(); +} + +void Radio::LoRaPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn, bool invIQ) +{ + if (radio.getPacketType() != PACKET_TYPE_LORA) + radio.setPacketType(PACKET_TYPE_LORA); + + pp.lora.PreambleLengthHi = preambleLen >> 8; + pp.lora.PreambleLengthLo = preambleLen; + pp.lora.HeaderType = fixLen; + pp.lora.CRCType = crcOn; + pp.lora.InvertIQ = invIQ; + + radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, 0, pp.buf); +} + +void Radio::GFSKModemConfig(unsigned bps, unsigned bw_hz, unsigned fdev_hz) +{ + ModulationParams_t mp; + uint32_t u32; + + if (radio.getPacketType() != PACKET_TYPE_GFSK) + radio.setPacketType(PACKET_TYPE_GFSK); + + u32 = 32 * (XTAL_FREQ_HZ / bps); + mp.gfsk.bitrateHi = u32 >> 16; // param1 + mp.gfsk.bitrateMid = u32 >> 8; // param2 + mp.gfsk.bitrateLo = u32; // param3 + mp.gfsk.PulseShape = GFSK_SHAPE_BT1_0; // param4 + // param5: + if (bw_hz < 5800) + mp.gfsk.bandwidth = GFSK_RX_BW_4800; + else if (bw_hz < 7300) + mp.gfsk.bandwidth = GFSK_RX_BW_5800; + else if (bw_hz < 9700) + mp.gfsk.bandwidth = GFSK_RX_BW_7300; + else if (bw_hz < 11700) + mp.gfsk.bandwidth = GFSK_RX_BW_9700; + else if (bw_hz < 14600) + mp.gfsk.bandwidth = GFSK_RX_BW_11700; + else if (bw_hz < 19500) + mp.gfsk.bandwidth = GFSK_RX_BW_14600; + else if (bw_hz < 23400) + mp.gfsk.bandwidth = GFSK_RX_BW_19500; + else if (bw_hz < 29300) + mp.gfsk.bandwidth = GFSK_RX_BW_23400; + else if (bw_hz < 39000) + mp.gfsk.bandwidth = GFSK_RX_BW_29300; + else if (bw_hz < 46900) + mp.gfsk.bandwidth = GFSK_RX_BW_39000; + else if (bw_hz < 58600) + mp.gfsk.bandwidth = GFSK_RX_BW_46900; + else if (bw_hz < 78200) + mp.gfsk.bandwidth = GFSK_RX_BW_58600; + else if (bw_hz < 93800) + mp.gfsk.bandwidth = GFSK_RX_BW_78200; + else if (bw_hz < 117300) + mp.gfsk.bandwidth = GFSK_RX_BW_93800; + else if (bw_hz < 156200) + mp.gfsk.bandwidth = GFSK_RX_BW_117300; + else if (bw_hz < 187200) + mp.gfsk.bandwidth = GFSK_RX_BW_156200; + else if (bw_hz < 234300) + mp.gfsk.bandwidth = GFSK_RX_BW_187200; + else if (bw_hz < 312000) + mp.gfsk.bandwidth = GFSK_RX_BW_234300; + else if (bw_hz < 373600) + mp.gfsk.bandwidth = GFSK_RX_BW_312000; + else if (bw_hz < 467000) + mp.gfsk.bandwidth = GFSK_RX_BW_373600; + else + mp.gfsk.bandwidth = GFSK_RX_BW_467000; + + if (fdev_hz > 0) { + u32 = fdev_hz / 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, 0, mp.buf); +} + +void Radio::GFSKPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn) +{ + if (radio.getPacketType() != PACKET_TYPE_GFSK) + radio.setPacketType(PACKET_TYPE_GFSK); + + 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; + + //TODO pp.gfsk.PayloadLength = ; + + radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, 0, pp.buf); +} + +void Radio::LoRaModemConfig(unsigned bwKHz, uint8_t sf, uint8_t cr) +{ + ModulationParams_t mp; + float khz, sp; + + if (radio.getPacketType() != PACKET_TYPE_LORA) + radio.setPacketType(PACKET_TYPE_LORA); + + if (bwKHz > 250) { + mp.lora.bandwidth = LORA_BW_500; + khz = 500; + } else if (bwKHz > 125) { + mp.lora.bandwidth = LORA_BW_250; + khz = 250; + } else if (bwKHz > 63) { + mp.lora.bandwidth = LORA_BW_125; + khz = 125; + } else if (bwKHz > 42) { + mp.lora.bandwidth = LORA_BW_62; + khz = 62.5; + } else if (bwKHz > 32) { + mp.lora.bandwidth = LORA_BW_41; + khz = 41.67; + } else if (bwKHz > 21) { + mp.lora.bandwidth = LORA_BW_31; + khz = 31.25; + } else if (bwKHz > 16) { + mp.lora.bandwidth = LORA_BW_20; + khz = 20.83; + } else if (bwKHz > 11) { + mp.lora.bandwidth = LORA_BW_15; + khz = 15.625; + } else if (bwKHz > 11) { + mp.lora.bandwidth = LORA_BW_10; + khz = 10.42; + } else { + mp.lora.bandwidth = LORA_BW_7; + khz = 7.81; + } + + mp.lora.spreadingFactor = sf; + mp.lora.codingRate = cr; + + 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, 0, mp.buf); + +} + +void Radio::SetLoRaSymbolTimeout(uint8_t symbs) +{ + if (radio.getPacketType() != PACKET_TYPE_LORA) + radio.setPacketType(PACKET_TYPE_LORA); + + radio.xfer(OPCODE_SET_LORA_SYMBOL_TIMEOUT, 1, 0, &symbs); +} + +int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh) +{ + uint8_t buf[8]; + uint8_t pktType = radio.getPacketType(); + + buf[0] = 0; // TX base address + buf[1] = 0; // RX base address + radio.xfer(OPCODE_SET_BUFFER_BASE_ADDR, 2, 0, buf); + + if (pktType == PACKET_TYPE_GFSK) { + pp.gfsk.PayloadLength = size; + radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, 0, pp.buf); + } else if (pktType == PACKET_TYPE_LORA) { + pp.lora.PayloadLength = size; + radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, 0, pp.buf); + } + + { + 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, 0, buf); + } + + antswPower = 1; + + if (maxListenTime > 0) { + int rssi; + us_timestamp_t startAt, chFreeAt, now; + uint8_t symbs = 0; + + radio.xfer(OPCODE_SET_LORA_SYMBOL_TIMEOUT, 1, 0, &symbs); + + 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, 0, 2, buf); + rssi = buf[1] / -2; + } while (rssi > rssiThresh); + chFreeAt = lpt.read_us(); + do { + now = lpt.read_us(); + radio.xfer(OPCODE_GET_RSSIINST, 0, 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, 0, buf); + } else if (modem == MODEM_LORA) { + pp.lora.PayloadLength = max; + memcpy(buf, pp.buf, 6); + radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, 0, buf); + } +} + +void Radio::dio1_top_half() +{ + irqAt = lpt.read_us(); + + if (radio.chipMode == CHIPMODE_TX) { + /* TxDone handling requires low latency */ + if (RadioEvents->TxDone_topHalf) { + RadioEvents->TxDone_topHalf(); + } + } else { +#ifdef TARGET_FF_MORPHO + 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(size, rssi, snr); +} + +void Radio::txDoneBottom() +{ + if (RadioEvents->TxDone_botHalf) + RadioEvents->TxDone_botHalf(); +} + +void Radio::Init(const RadioEvents_t* e) +{ + radio.txDone = txDoneBottom; + radio.rxDone = rx_done; + radio.timeout = timeout_callback; + radio.chipModeChange = chipModeChange; + radio.dio1_topHalf = dio1_top_half; + + RadioEvents = e; + lpt.start(); + + radio.SetDIO2AsRfSwitchCtrl(1); +} + +void Radio::service() +{ + 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); +} + +uint32_t Radio::lora_toa_us( uint8_t pktLen ) +{ + double bwKHz; + unsigned preambleLen; + ModulationParams_t mp; + + { + loraConfig1_t conf1; + conf1.octet = radio.readReg(REG_ADDR_LORA_CONFIG1, 1); + mp.lora.LowDatarateOptimize = conf1.bits.ppm_offset; + pp.lora.HeaderType = conf1.bits.implicit_header; + pp.lora.InvertIQ = conf1.bits.rx_invert_iq; + mp.lora.codingRate = conf1.bits.tx_coding_rate; + } + + { + loraConfig2_t conf2; + conf2.octet = radio.readReg(REG_ADDR_LORA_CONFIG2, 1); + pp.lora.CRCType = conf2.bits.tx_payload_crc16_en; + } + + + { + uint32_t val; + val = radio.readReg(REG_ADDR_LORA_PREAMBLE_SYMBNB, 2); + pp.lora.PreambleLengthHi = val >> 8; + pp.lora.PreambleLengthLo = val; + } + + preambleLen = (pp.lora.PreambleLengthHi << 8) + pp.lora.PreambleLengthLo; + + { + loraConfig0_t conf0; + conf0.octet = radio.readReg(REG_ADDR_LORA_CONFIG0, 1); + mp.lora.spreadingFactor = conf0.bits.modem_sf; + mp.lora.bandwidth = conf0.bits.modem_bw; + } + + switch (mp.lora.bandwidth) { + case LORA_BW_7: bwKHz = 7.81; break; + case LORA_BW_10: bwKHz = 10.42; break; + case LORA_BW_15: bwKHz = 15.625; break; + case LORA_BW_20: bwKHz = 20.83; break; + case LORA_BW_31: bwKHz = 31.25; break; + case LORA_BW_41: bwKHz = 41.67; break; + case LORA_BW_62: bwKHz = 62.5; break; + case LORA_BW_125: bwKHz = 125; break; + case LORA_BW_250: bwKHz = 250; break; + case LORA_BW_500: bwKHz = 500; break; + default: bwKHz = 0; break; + } + + // Symbol rate : time for one symbol (secs) + double rs = bwKHz / ( 1 << mp.lora.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 * mp.lora.spreadingFactor + + 28 + 16 * pp.lora.CRCType - + ( pp.lora.HeaderType ? 20 : 0 ) ) / + ( double )( 4 * ( mp.lora.spreadingFactor - + ( ( mp.lora.LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) * + ( mp.lora.codingRate + 4 ); + double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 ); + double tPayload = nPayload * ts; + // Time on air + double tOnAir = tPreamble + tPayload; + // return microseconds + return floor( tOnAir * 1000 + 0.999 ); +} + +#if 0 +void Radio::PrintStatus() +{ +/* uint8_t buf[4]; + status_t status; + IrqFlags_t irqFlags; + radio.xfer(OPCODE_GET_IRQ_STATUS, 0, 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, 0, 1, &status.octet); + radio.PrintChipStatus(status);*/ + { + loraConfig1_t conf1; + conf1.octet = radio.readReg(REG_ADDR_LORA_CONFIG1, 1); + printf("ldro%u %s %s cr%u\r\n", + conf1.bits.ppm_offset, + conf1.bits.implicit_header ? "fixed" : "var", + conf1.bits.rx_invert_iq ? "inv" : "std", + conf1.bits.tx_coding_rate + ); + } + + { + loraConfig2_t conf2; + conf2.octet = radio.readReg(REG_ADDR_LORA_CONFIG2, 1); + printf("crc16en:%u ", conf2.bits.tx_payload_crc16_en); + } + + + { + uint32_t val; + val = radio.readReg(REG_ADDR_LORA_PREAMBLE_SYMBNB, 2); + printf("prelen %lu ", val); + } + + { + loraConfig0_t conf0; + conf0.octet = radio.readReg(REG_ADDR_LORA_CONFIG0, 1); + printf("sf%u, bw%u ", conf0.bits.modem_sf, conf0.bits.modem_bw); + } + + printf("%.3fMHz\r\n", radio.getMHz()); +} +#endif /* if 0 */ + +#endif /* ..SX126x_H */