diff --git a/src/modules/SX1262.h b/src/modules/SX1262.h index f740dc37..eee52084 100644 --- a/src/modules/SX1262.h +++ b/src/modules/SX1262.h @@ -13,17 +13,17 @@ class SX1262: public SX126x { public: // constructor SX1262(Module* mod); - + // basic methods int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint16_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8); - + // configuration methods int16_t setFrequency(float freq); int16_t setOutputPower(int8_t power); - + private: - - + + }; #endif diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp index 4fa6477d..a3a7d2d9 100644 --- a/src/modules/SX126x.cpp +++ b/src/modules/SX126x.cpp @@ -2,24 +2,23 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPONENT) { _mod = mod; - _bw = SX126X_LORA_BW_125_0; - _bwKhz = 125.0; - _sf = 9; - _cr = SX126X_LORA_CR_4_7; - _ldro = 0x00; - _payloadLength = 255; - _crcType = SX126X_LORA_CRC_ON; - _preambleLength = 8; } int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength) { // set module properties _mod->init(USE_SPI, INT_BOTH); pinMode(_mod->getRx(), INPUT); - pinMode(_mod->getTx(), INPUT); - // reset module - reset(); + // BW in kHz and SF are required in order to calculate LDRO for setModulationParams + _bwKhz = bw; + _sf = sf; + + // initialize dummy configuration variables + _bw = SX126X_LORA_BW_125_0; + _cr = SX126X_LORA_CR_4_7; + _ldro = 0x00; + _crcType = SX126X_LORA_CRC_ON; + _preambleLength = preambleLength; // get status and errors getStatus(); @@ -32,12 +31,12 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1 config(); // configure publicly accessible settings - int16_t state = setBandwidth(bw); + int16_t state = setSpreadingFactor(sf); if(state != ERR_NONE) { return(state); } - state = setSpreadingFactor(sf); + state = setBandwidth(bw); if(state != ERR_NONE) { return(state); } @@ -61,7 +60,79 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1 } int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { + // set mode to standby + int16_t state = standby(); + // get currently active modem + uint8_t modem = getPacketType(); + if(modem == SX126X_PACKET_TYPE_LORA) { + // check packet length + if(len >= 256) { + return(ERR_PACKET_TOO_LONG); + } + + // calculate timeout (150% of expected time-on-air) + float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz; + float sfCoeff1 = 4.25; + float sfCoeff2 = 8.0; + if(_sf == 5 || _sf == 6) { + sfCoeff1 = 6.25; + sfCoeff2 = 0.0; + } + uint8_t sfDivisor = 4*_sf; + if(symbolLength >= 16.0) { + sfDivisor = 4*(_sf - 2); + } + float nSymbol = _preambleLength + sfCoeff1 + 8 + ceil(max(8.0 * len + (_crcType * 16.0) - 4.0 * _sf + sfCoeff2 + 20.0, 0.0) / sfDivisor) * (_cr + 4); + uint32_t timeout = (uint32_t)(symbolLength * nSymbol * 1.5); + DEBUG_PRINTLN(timeout); + + // set DIO mapping + setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE); + + // set packet length + setPacketParams(_preambleLength, _crcType, len); + + // set buffer pointers + setBufferBaseAddress(); + + // write packet to buffer + writeBuffer(data, len); + + // clear interrupt flags + clearIrqStatus(); + + // start transmission + uint32_t timeoutValue = (uint32_t)((float)timeout / 0.015625); + setTx(timeoutValue); + //DEBUG_PRINTLN(digitalRead(_mod->getRx())); + + // wait for BUSY to go low (= PA ramp up done) + while(digitalRead(_mod->getRx())); + + // wait for packet transmission or timeout + uint32_t start = millis(); + while(!digitalRead(_mod->getInt0())) { + if(millis() - start > timeout) { + clearIrqStatus(); + return(ERR_TX_TIMEOUT); + } + } + uint32_t elapsed = millis() - start; + + // update data rate + _dataRate = (len*8.0)/((float)elapsed/1000.0); + + // clear interrupt flags + clearIrqStatus(); + + return(ERR_NONE); + + } else if(modem == SX126X_PACKET_TYPE_GFSK) { + + } + + return(ERR_UNKNOWN); } int16_t SX126x::receive(uint8_t* data, size_t len) { @@ -100,16 +171,6 @@ int16_t SX126x::standby(uint8_t mode) { return(ERR_NONE); } -void SX126x::reset() { - delay(10); - pinMode(_mod->getTx(), OUTPUT); - digitalWrite(_mod->getTx(), LOW); - delay(20); - digitalWrite(_mod->getTx(), HIGH); - pinMode(_mod->getTx(), INPUT); - delay(10); -} - int16_t SX126x::setBandwidth(float bw) { // check active modem if(getPacketType() != SX126X_PACKET_TYPE_LORA) { @@ -205,12 +266,12 @@ int16_t SX126x::setCurrentLimit(float currentLimit) { int16_t SX126x::setPreambleLength(uint16_t preambleLength) { // update packet parameters _preambleLength = preambleLength; - setPacketParams(_preambleLength, _payloadLength, _crcType); + setPacketParams(_preambleLength, _crcType); return(ERR_NONE); } float SX126x::getDataRate() { - + return(_dataRate); } int16_t SX126x::setFrequencyDeviation(float freqDev) { @@ -246,6 +307,14 @@ void SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { delete[] dat; } +void SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { + uint8_t* dat = new uint8_t[1 + numBytes]; + dat[0] = offset; + memcpy(dat + 1, data, numBytes); + SPIwriteCommand(SX126X_CMD_WRITE_BUFFER, data, 1 + numBytes); + delete[] dat; +} + void SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), @@ -292,46 +361,20 @@ void SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldr SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 4); } -void SX126x::setPacketParams(uint16_t preambleLength, uint8_t payloadLength, uint8_t crcType, uint8_t headerType, uint8_t invertIQ) { +void SX126x::setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ) { uint8_t data[6] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ}; SPIwriteCommand(SX126X_CMD_SET_PACKET_PARAMS, data, 6); } +void SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { + uint8_t data[2] = {txBaseAddress, rxBaseAddress}; + SPIwriteCommand(SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2); +} + uint8_t SX126x::getStatus() { - /*uint8_t data[1]; + uint8_t data[1]; SPIreadCommand(SX126X_CMD_GET_STATUS, data, 1); - return(data[0]);*/ - - // get pointer to used SPI interface - SPIClass* spi = _mod->getSpi(); - - // ensure BUSY is low (state meachine ready) - // TODO timeout - while(digitalRead(_mod->getRx())); - - // start transfer - digitalWrite(_mod->getCs(), LOW); - spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); - - // send command byte - spi->transfer(SX126X_CMD_GET_STATUS); - DEBUG_PRINT(SX126X_CMD_GET_STATUS, HEX); - DEBUG_PRINT('\t'); - - // get status - uint8_t status = spi->transfer(SX126X_CMD_NOP) & 0b01111110; - DEBUG_PRINTLN(status, HEX); - - // stop transfer - spi->endTransaction(); - digitalWrite(_mod->getCs(), HIGH); - - // wait for BUSY to go high and then low - // TODO timeout - delayMicroseconds(1); - while(digitalRead(_mod->getRx())); - - return(status); + return(data[0]); } uint8_t SX126x::getRssiInt() { @@ -382,25 +425,19 @@ int16_t SX126x::setFrequencyRaw(float freq, bool calibrate) { } int16_t SX126x::config() { - // set DIO2 as RF switch + // set DIO2 as IRQ uint8_t* data = new uint8_t[1]; - data[0] = SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL; + data[0] = SX126X_DIO2_AS_IRQ; SPIwriteCommand(SX126X_DIO2_AS_RF_SWITCH, data, 1); // set regulator mode data[0] = SX126X_REGULATOR_DC_DC; SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1); - // set buffer base address - delete[] data; - data = new uint8_t[2]; - data[0] = 0x00; - data[1] = 0x00; - SPIwriteCommand(SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2); + // reset buffer base address + setBufferBaseAddress(); // set LoRa mode - delete[] data; - data = new uint8_t[1]; data[0] = SX126X_PACKET_TYPE_LORA; SPIwriteCommand(SX126X_CMD_SET_PACKET_TYPE, data, 1); @@ -420,6 +457,12 @@ int16_t SX126x::config() { data[6] = 0x00; SPIwriteCommand(SX126X_CMD_SET_CAD_PARAMS, data, 7); + // clear IRQ + clearIrqStatus(); + setDioIrqParams(SX126X_IRQ_NONE, SX126X_IRQ_NONE); + + delete[] data; + return(ERR_NONE); } diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h index 909e32f8..9352a829 100644 --- a/src/modules/SX126x.h +++ b/src/modules/SX126x.h @@ -330,7 +330,6 @@ class SX126x: public PhysicalLayer { int16_t receiveDirect(); int16_t sleep(); int16_t standby(uint8_t mode = SX126X_STANDBY_RC); - void reset(); // configuration methods int16_t setBandwidth(float bw); @@ -349,13 +348,15 @@ class SX126x: public PhysicalLayer { void setCad(); void setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = SX126X_PA_CONFIG_PA_LUT); void writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); - void setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask = 0x0000); + void writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); + void setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX126X_IRQ_NONE, uint16_t dio3Mask = SX126X_IRQ_NONE); void clearIrqStatus(uint16_t clearIrqParams = 0xFFFF); void setRfFrequency(uint32_t frf); uint8_t getPacketType(); - void setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_40U); + void setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U); void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF); - void setPacketParams(uint16_t preambleLength, uint8_t payloadLength, uint8_t crcType, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_INVERTED); + void setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength = 0xFF, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_INVERTED); + void setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); uint8_t getStatus(); uint8_t getRssiInt(); uint16_t getDeviceErrors(); @@ -366,10 +367,12 @@ class SX126x: public PhysicalLayer { private: Module* _mod; - uint8_t _bw, _sf, _cr, _ldro, _payloadLength, _crcType; + uint8_t _bw, _sf, _cr, _ldro, _crcType; uint16_t _preambleLength; float _bwKhz; + float _dataRate; + int16_t config(); // common low-level SPI interface