From 3a141a05b53fc20da93895ae7c1f32b6d030e3f4 Mon Sep 17 00:00:00 2001 From: Matt Mason Date: Sun, 18 Aug 2024 19:46:36 -0500 Subject: [PATCH 1/9] Initial commit --- src/LoRa.cpp | 260 ++++++++++++++++++++++++++++----------------------- src/LoRa.h | 63 ++++++------- 2 files changed, 171 insertions(+), 152 deletions(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 210a589..1d89ce5 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -73,8 +73,10 @@ LoRaClass::LoRaClass() : _spi(&LORA_DEFAULT_SPI), _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _frequency(0), - _packetIndex(0), _implicitHeaderMode(0), + _transmitting(false), + _packetIndex(0), + _available(0), _onReceive(NULL), _onTxDone(NULL) { @@ -82,27 +84,11 @@ LoRaClass::LoRaClass() : setTimeout(0); } -int LoRaClass::begin(long frequency) +bool LoRaClass::begin(long frequency) { -#if defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) - pinMode(LORA_IRQ_DUMB, OUTPUT); - digitalWrite(LORA_IRQ_DUMB, LOW); - - // Hardware reset - pinMode(LORA_BOOT0, OUTPUT); - digitalWrite(LORA_BOOT0, LOW); - - pinMode(LORA_RESET, OUTPUT); - digitalWrite(LORA_RESET, HIGH); - delay(200); - digitalWrite(LORA_RESET, LOW); - delay(200); - digitalWrite(LORA_RESET, HIGH); - delay(50); -#endif - // setup pins pinMode(_ss, OUTPUT); + pinMode(_dio0, INPUT); // set SS high digitalWrite(_ss, HIGH); @@ -147,6 +133,12 @@ int LoRaClass::begin(long frequency) // put in standby mode idle(); + // attach ISR +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); +#endif + attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); + return 1; } @@ -159,9 +151,9 @@ void LoRaClass::end() _spi->end(); } -int LoRaClass::beginPacket(int implicitHeader) +bool LoRaClass::beginPacket(int implicitHeader) { - if (isTransmitting()) { + if (_transmitting) { return 0; } @@ -175,51 +167,53 @@ int LoRaClass::beginPacket(int implicitHeader) } // reset FIFO address and paload length - writeRegister(REG_FIFO_ADDR_PTR, 0); + resetFifo(); writeRegister(REG_PAYLOAD_LENGTH, 0); return 1; } -int LoRaClass::endPacket(bool async) +bool LoRaClass::endPacket(bool async) { - if ((async) && (_onTxDone)) - writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE + // if ((async) || (_onTxDone)) + writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE // put in TX mode writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); + _transmitting = true; if (!async) { // wait for TX done - while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { + while (_transmitting) {//(readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { yield(); } + // clear IRQ's - writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); + // writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); } return 1; } -bool LoRaClass::isTransmitting() -{ - if ((readRegister(REG_OP_MODE) & MODE_TX) == MODE_TX) { - return true; - } +// bool LoRaClass::isTransmitting() +// { +// if ((readRegister(REG_OP_MODE) & MODE_TX) == MODE_TX) { +// return true; +// } - if (readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) { - // clear IRQ's - writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); - } +// if (readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) { +// // clear IRQ's +// writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); +// } - return false; -} +// return false; +// } -int LoRaClass::parsePacket(int size) +uint8_t LoRaClass::parsePacket(uint8_t size) { - int packetLength = 0; - int irqFlags = readRegister(REG_IRQ_FLAGS); + uint8_t packetLength = 0; + uint8_t irqFlags = readRegister(REG_IRQ_FLAGS); if (size > 0) { implicitHeaderMode(); @@ -238,9 +232,9 @@ int LoRaClass::parsePacket(int size) // read packet length if (_implicitHeaderMode) { - packetLength = readRegister(REG_PAYLOAD_LENGTH); + _available = readRegister(REG_PAYLOAD_LENGTH); } else { - packetLength = readRegister(REG_RX_NB_BYTES); + _available = readRegister(REG_RX_NB_BYTES); } // set FIFO address to current RX address @@ -252,23 +246,23 @@ int LoRaClass::parsePacket(int size) // not currently in RX mode // reset FIFO address - writeRegister(REG_FIFO_ADDR_PTR, 0); + resetFifo(); // put in single RX mode writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); } - return packetLength; + return _available; } int LoRaClass::packetRssi() { - return (readRegister(REG_PKT_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT)); + return readRegister(REG_PKT_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); } float LoRaClass::packetSnr() { - return ((int8_t)readRegister(REG_PKT_SNR_VALUE)) * 0.25; + return (int8_t)readRegister(REG_PKT_SNR_VALUE) * 0.25f; } long LoRaClass::packetFrequencyError() @@ -292,7 +286,7 @@ long LoRaClass::packetFrequencyError() int LoRaClass::rssi() { - return (readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT)); + return readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); } size_t LoRaClass::write(uint8_t byte) @@ -302,15 +296,15 @@ size_t LoRaClass::write(uint8_t byte) size_t LoRaClass::write(const uint8_t *buffer, size_t size) { - int currentLength = readRegister(REG_PAYLOAD_LENGTH); + uint8_t currentLength = readRegister(REG_PAYLOAD_LENGTH); // check size - if ((currentLength + size) > MAX_PKT_LENGTH) { + if ((size + currentLength) > MAX_PKT_LENGTH) { size = MAX_PKT_LENGTH - currentLength; } // write data - for (size_t i = 0; i < size; i++) { + for (uint8_t i = 0; i < size; i++) { writeRegister(REG_FIFO, buffer[i]); } @@ -322,7 +316,10 @@ size_t LoRaClass::write(const uint8_t *buffer, size_t size) int LoRaClass::available() { - return (readRegister(REG_RX_NB_BYTES) - _packetIndex); + if (_available > _packetIndex) + return _available - _packetIndex; + return 0; + // return (readRegister(REG_RX_NB_BYTES) - _packetIndex); } int LoRaClass::read() @@ -343,7 +340,7 @@ int LoRaClass::peek() } // store current FIFO address - int currentAddress = readRegister(REG_FIFO_ADDR_PTR); + uint8_t currentAddress = readRegister(REG_FIFO_ADDR_PTR); // read uint8_t b = readRegister(REG_FIFO); @@ -358,45 +355,47 @@ void LoRaClass::flush() { } -#ifndef ARDUINO_SAMD_MKRWAN1300 -void LoRaClass::onReceive(void(*callback)(int)) +void LoRaClass::onReceive(void(*callback)(uint8_t)) { _onReceive = callback; - if (callback) { - pinMode(_dio0, INPUT); -#ifdef SPI_HAS_NOTUSINGINTERRUPT - SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); -#endif - attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); - } else { - detachInterrupt(digitalPinToInterrupt(_dio0)); -#ifdef SPI_HAS_NOTUSINGINTERRUPT - SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); -#endif - } +// if (callback) { +// pinMode(_dio0, INPUT); +// #ifdef SPI_HAS_NOTUSINGINTERRUPT +// SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); +// #endif +// attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); +// } else { +// detachInterrupt(digitalPinToInterrupt(_dio0)); +// #ifdef SPI_HAS_NOTUSINGINTERRUPT +// SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); +// #endif +// } } void LoRaClass::onTxDone(void(*callback)()) { _onTxDone = callback; - if (callback) { - pinMode(_dio0, INPUT); -#ifdef SPI_HAS_NOTUSINGINTERRUPT - SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); -#endif - attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); - } else { - detachInterrupt(digitalPinToInterrupt(_dio0)); -#ifdef SPI_HAS_NOTUSINGINTERRUPT - SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); -#endif - } +// if (callback) { +// pinMode(_dio0, INPUT); +// #ifdef SPI_HAS_NOTUSINGINTERRUPT +// SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); +// #endif +// attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); +// } else { +// detachInterrupt(digitalPinToInterrupt(_dio0)); +// #ifdef SPI_HAS_NOTUSINGINTERRUPT +// SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); +// #endif +// } } -void LoRaClass::receive(int size) +void LoRaClass::continuousRx(uint8_t size) { + // wait for any existing transmission to complete + while (_transmitting) + yield(); writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE @@ -410,7 +409,25 @@ void LoRaClass::receive(int size) writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); } -#endif + +void LoRaClass::singleRx() +{ + if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { + // not currently in RX mode + + // wait for any existing transmission to complete + while (_transmitting) + yield(); + + // reset FIFO address + resetFifo(); + + writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE + + // put in single RX mode + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); + } +} void LoRaClass::idle() { @@ -422,7 +439,7 @@ void LoRaClass::sleep() writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); } -void LoRaClass::setTxPower(int level, int outputPin) +void LoRaClass::setTxPower(uint8_t level, uint8_t outputPin) { if (PA_OUTPUT_RFO_PIN == outputPin) { // RFO @@ -470,12 +487,12 @@ void LoRaClass::setFrequency(long frequency) writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); } -int LoRaClass::getSpreadingFactor() +uint8_t LoRaClass::getSpreadingFactor() { return readRegister(REG_MODEM_CONFIG_2) >> 4; } -void LoRaClass::setSpreadingFactor(int sf) +void LoRaClass::setSpreadingFactor(uint8_t sf) { if (sf < 6) { sf = 6; @@ -497,7 +514,7 @@ void LoRaClass::setSpreadingFactor(int sf) long LoRaClass::getSignalBandwidth() { - byte bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); + uint8_t bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); switch (bw) { case 0: return 7.8E3; @@ -517,7 +534,7 @@ long LoRaClass::getSignalBandwidth() void LoRaClass::setSignalBandwidth(long sbw) { - int bw; + uint8_t bw; if (sbw <= 7.8E3) { bw = 0; @@ -548,17 +565,18 @@ void LoRaClass::setSignalBandwidth(long sbw) void LoRaClass::setLdoFlag() { // Section 4.1.1.5 - long symbolDuration = 1000 / ( getSignalBandwidth() / (1L << getSpreadingFactor()) ) ; + float symbolDuration = 1000.0f / ((float)getSignalBandwidth() / (1u << getSpreadingFactor())); + Serial.print("symbolDuration: "); Serial.println(symbolDuration); // Section 4.1.1.6 - boolean ldoOn = symbolDuration > 16; + bool ldoOn = symbolDuration > 16.0f; uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); bitWrite(config3, 3, ldoOn); writeRegister(REG_MODEM_CONFIG_3, config3); } -void LoRaClass::setCodingRate4(int denominator) +void LoRaClass::setCodingRate4(uint8_t denominator) { if (denominator < 5) { denominator = 5; @@ -566,18 +584,18 @@ void LoRaClass::setCodingRate4(int denominator) denominator = 8; } - int cr = denominator - 4; + uint8_t cr = denominator - 4; writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); } -void LoRaClass::setPreambleLength(long length) +void LoRaClass::setPreambleLength(uint16_t length) { writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); } -void LoRaClass::setSyncWord(int sw) +void LoRaClass::setSyncWord(uint8_t sw) { writeRegister(REG_SYNC_WORD, sw); } @@ -630,10 +648,10 @@ void LoRaClass::setGain(uint8_t gain) // set gain if (gain == 0) { // if gain = 0, enable AGC - writeRegister(REG_MODEM_CONFIG_3, 0x04); + writeRegister(REG_MODEM_CONFIG_3, 0x04); // TODO use bit set } else { // disable AGC - writeRegister(REG_MODEM_CONFIG_3, 0x00); + writeRegister(REG_MODEM_CONFIG_3, 0x00); // TODO use bit set // clear Gain and set LNA boost writeRegister(REG_LNA, 0x03); @@ -643,12 +661,12 @@ void LoRaClass::setGain(uint8_t gain) } } -byte LoRaClass::random() +uint8_t LoRaClass::random() { return readRegister(REG_RSSI_WIDEBAND); } -void LoRaClass::setPins(int ss, int reset, int dio0) +void LoRaClass::setPins(uint8_t ss, uint8_t reset, uint8_t dio0) { _ss = ss; _reset = reset; @@ -667,7 +685,7 @@ void LoRaClass::setSPIFrequency(uint32_t frequency) void LoRaClass::dumpRegisters(Stream& out) { - for (int i = 0; i < 128; i++) { + for (uint8_t i = 0; i < 128; i++) { out.print("0x"); out.print(i, HEX); out.print(": 0x"); @@ -691,35 +709,42 @@ void LoRaClass::implicitHeaderMode() void LoRaClass::handleDio0Rise() { - int irqFlags = readRegister(REG_IRQ_FLAGS); + uint8_t irqFlags = readRegister(REG_IRQ_FLAGS); + // Serial.print("---- IRQ: "); Serial.println(irqFlags, BIN); // clear IRQ's writeRegister(REG_IRQ_FLAGS, irqFlags); - if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { - - if ((irqFlags & IRQ_RX_DONE_MASK) != 0) { - // received a packet - _packetIndex = 0; + if (irqFlags & IRQ_TX_DONE_MASK) { + _transmitting = false; + if (_onTxDone) { + _onTxDone(); + } + } + else if ((irqFlags & IRQ_RX_DONE_MASK) && !(irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK)) { + // received a packet + _packetIndex = 0; - // read packet length - int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH) : readRegister(REG_RX_NB_BYTES); + // read packet length + _available = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH) : readRegister(REG_RX_NB_BYTES); - // set FIFO address to current RX address - writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); + // set FIFO address to current RX address + writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); - if (_onReceive) { - _onReceive(packetLength); - } - } - else if ((irqFlags & IRQ_TX_DONE_MASK) != 0) { - if (_onTxDone) { - _onTxDone(); - } + if (_onReceive) { + _onReceive(_available); } } } +void LoRaClass::resetFifo() +{ + // reset FIFO address + writeRegister(REG_FIFO_ADDR_PTR, 0); + _available = 0; + _packetIndex = 0; +} + uint8_t LoRaClass::readRegister(uint8_t address) { return singleTransfer(address & 0x7f, 0x00); @@ -746,6 +771,11 @@ uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value) return response; } +void LoRaClass::debug() +{ + Serial.print("mode: "); Serial.print(readRegister(REG_OP_MODE), BIN); Serial.print(" status: "); Serial.println(readRegister(0x18), BIN); +} + ISR_PREFIX void LoRaClass::onDio0Rise() { LoRa.handleDio0Rise(); diff --git a/src/LoRa.h b/src/LoRa.h index b312db5..18e298d 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -7,25 +7,11 @@ #include #include -#if defined(ARDUINO_SAMD_MKRWAN1300) -#define LORA_DEFAULT_SPI SPI1 -#define LORA_DEFAULT_SPI_FREQUENCY 200000 -#define LORA_DEFAULT_SS_PIN LORA_IRQ_DUMB -#define LORA_DEFAULT_RESET_PIN -1 -#define LORA_DEFAULT_DIO0_PIN -1 -#elif defined(ARDUINO_SAMD_MKRWAN1310) -#define LORA_DEFAULT_SPI SPI1 -#define LORA_DEFAULT_SPI_FREQUENCY 200000 -#define LORA_DEFAULT_SS_PIN LORA_IRQ_DUMB -#define LORA_DEFAULT_RESET_PIN -1 -#define LORA_DEFAULT_DIO0_PIN LORA_IRQ -#else #define LORA_DEFAULT_SPI SPI #define LORA_DEFAULT_SPI_FREQUENCY 8E6 #define LORA_DEFAULT_SS_PIN 10 #define LORA_DEFAULT_RESET_PIN 9 #define LORA_DEFAULT_DIO0_PIN 2 -#endif #define PA_OUTPUT_RFO_PIN 0 #define PA_OUTPUT_PA_BOOST_PIN 1 @@ -34,13 +20,13 @@ class LoRaClass : public Stream { public: LoRaClass(); - int begin(long frequency); + bool begin(long frequency); void end(); - int beginPacket(int implicitHeader = false); - int endPacket(bool async = false); + bool beginPacket(int implicitHeader = false); + bool endPacket(bool async = false); - int parsePacket(int size = 0); + uint8_t parsePacket(uint8_t size = 0); int packetRssi(); float packetSnr(); long packetFrequencyError(); @@ -57,22 +43,21 @@ class LoRaClass : public Stream { virtual int peek(); virtual void flush(); -#ifndef ARDUINO_SAMD_MKRWAN1300 - void onReceive(void(*callback)(int)); + void onReceive(void(*callback)(uint8_t)); void onTxDone(void(*callback)()); - void receive(int size = 0); -#endif + void continuousRx(uint8_t size = 0); + void singleRx(); void idle(); void sleep(); - void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); + void setTxPower(uint8_t level, uint8_t outputPin = PA_OUTPUT_PA_BOOST_PIN); void setFrequency(long frequency); - void setSpreadingFactor(int sf); + void setSpreadingFactor(uint8_t sf); void setSignalBandwidth(long sbw); - void setCodingRate4(int denominator); - void setPreambleLength(long length); - void setSyncWord(int sw); + void setCodingRate4(uint8_t denominator); + void setPreambleLength(uint16_t length); + void setSyncWord(uint8_t sw); void enableCrc(); void disableCrc(); void enableInvertIQ(); @@ -86,22 +71,24 @@ class LoRaClass : public Stream { void crc() { enableCrc(); } void noCrc() { disableCrc(); } - byte random(); + uint8_t random(); - void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN); + void setPins(uint8_t ss = LORA_DEFAULT_SS_PIN, uint8_t reset = LORA_DEFAULT_RESET_PIN, uint8_t dio0 = LORA_DEFAULT_DIO0_PIN); void setSPI(SPIClass& spi); void setSPIFrequency(uint32_t frequency); void dumpRegisters(Stream& out); + void debug(); private: void explicitHeaderMode(); void implicitHeaderMode(); void handleDio0Rise(); - bool isTransmitting(); + // bool isTransmitting(); + void resetFifo(); - int getSpreadingFactor(); + uint8_t getSpreadingFactor(); long getSignalBandwidth(); void setLdoFlag(); @@ -115,13 +102,15 @@ class LoRaClass : public Stream { private: SPISettings _spiSettings; SPIClass* _spi; - int _ss; - int _reset; - int _dio0; + uint8_t _ss; + uint8_t _reset; + uint8_t _dio0; long _frequency; - int _packetIndex; - int _implicitHeaderMode; - void (*_onReceive)(int); + bool _implicitHeaderMode; + volatile bool _transmitting; + volatile uint8_t _packetIndex; + volatile uint8_t _available; + void (*_onReceive)(uint8_t); void (*_onTxDone)(); }; From d6962f670ca5e770b8efd7312de5642a4fda1f12 Mon Sep 17 00:00:00 2001 From: Matt Mason Date: Sun, 18 Aug 2024 20:50:37 -0500 Subject: [PATCH 2/9] Change indentation to 4 spaces --- src/LoRa.cpp | 760 +++++++++++++++++++++++++-------------------------- src/LoRa.h | 170 ++++++------ 2 files changed, 465 insertions(+), 465 deletions(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 1d89ce5..9cbfef0 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -69,131 +69,131 @@ #endif LoRaClass::LoRaClass() : - _spiSettings(LORA_DEFAULT_SPI_FREQUENCY, MSBFIRST, SPI_MODE0), - _spi(&LORA_DEFAULT_SPI), - _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), - _frequency(0), - _implicitHeaderMode(0), - _transmitting(false), - _packetIndex(0), - _available(0), - _onReceive(NULL), - _onTxDone(NULL) + _spiSettings(LORA_DEFAULT_SPI_FREQUENCY, MSBFIRST, SPI_MODE0), + _spi(&LORA_DEFAULT_SPI), + _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), + _frequency(0), + _implicitHeaderMode(0), + _transmitting(false), + _packetIndex(0), + _available(0), + _onReceive(NULL), + _onTxDone(NULL) { - // overide Stream timeout value - setTimeout(0); + // overide Stream timeout value + setTimeout(0); } bool LoRaClass::begin(long frequency) { - // setup pins - pinMode(_ss, OUTPUT); - pinMode(_dio0, INPUT); - // set SS high - digitalWrite(_ss, HIGH); + // setup pins + pinMode(_ss, OUTPUT); + pinMode(_dio0, INPUT); + // set SS high + digitalWrite(_ss, HIGH); - if (_reset != -1) { - pinMode(_reset, OUTPUT); + if (_reset != -1) { + pinMode(_reset, OUTPUT); - // perform reset - digitalWrite(_reset, LOW); - delay(10); - digitalWrite(_reset, HIGH); - delay(10); - } + // perform reset + digitalWrite(_reset, LOW); + delay(10); + digitalWrite(_reset, HIGH); + delay(10); + } - // start SPI - _spi->begin(); + // start SPI + _spi->begin(); - // check version - uint8_t version = readRegister(REG_VERSION); - if (version != 0x12) { - return 0; - } + // check version + uint8_t version = readRegister(REG_VERSION); + if (version != 0x12) { + return 0; + } - // put in sleep mode - sleep(); + // put in sleep mode + sleep(); - // set frequency - setFrequency(frequency); + // set frequency + setFrequency(frequency); - // set base addresses - writeRegister(REG_FIFO_TX_BASE_ADDR, 0); - writeRegister(REG_FIFO_RX_BASE_ADDR, 0); + // set base addresses + writeRegister(REG_FIFO_TX_BASE_ADDR, 0); + writeRegister(REG_FIFO_RX_BASE_ADDR, 0); - // set LNA boost - writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03); + // set LNA boost + writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03); - // set auto AGC - writeRegister(REG_MODEM_CONFIG_3, 0x04); + // set auto AGC + writeRegister(REG_MODEM_CONFIG_3, 0x04); - // set output power to 17 dBm - setTxPower(17); + // set output power to 17 dBm + setTxPower(17); - // put in standby mode - idle(); + // put in standby mode + idle(); - // attach ISR + // attach ISR #ifdef SPI_HAS_NOTUSINGINTERRUPT SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); #endif attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); - return 1; + return 1; } void LoRaClass::end() { - // put in sleep mode - sleep(); + // put in sleep mode + sleep(); - // stop SPI - _spi->end(); + // stop SPI + _spi->end(); } bool LoRaClass::beginPacket(int implicitHeader) { - if (_transmitting) { - return 0; - } + if (_transmitting) { + return 0; + } - // put in standby mode - idle(); + // put in standby mode + idle(); - if (implicitHeader) { - implicitHeaderMode(); - } else { - explicitHeaderMode(); - } + if (implicitHeader) { + implicitHeaderMode(); + } else { + explicitHeaderMode(); + } - // reset FIFO address and paload length - resetFifo(); - writeRegister(REG_PAYLOAD_LENGTH, 0); + // reset FIFO address and paload length + resetFifo(); + writeRegister(REG_PAYLOAD_LENGTH, 0); - return 1; + return 1; } bool LoRaClass::endPacket(bool async) { - - // if ((async) || (_onTxDone)) - writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE - // put in TX mode - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); - _transmitting = true; + // if ((async) || (_onTxDone)) + writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE - if (!async) { - // wait for TX done - while (_transmitting) {//(readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { - yield(); - } + // put in TX mode + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); + _transmitting = true; - // clear IRQ's - // writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); - } + if (!async) { + // wait for TX done + while (_transmitting) {//(readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { + yield(); + } - return 1; + // clear IRQ's + // writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); + } + + return 1; } // bool LoRaClass::isTransmitting() @@ -212,143 +212,143 @@ bool LoRaClass::endPacket(bool async) uint8_t LoRaClass::parsePacket(uint8_t size) { - uint8_t packetLength = 0; - uint8_t irqFlags = readRegister(REG_IRQ_FLAGS); + uint8_t packetLength = 0; + uint8_t irqFlags = readRegister(REG_IRQ_FLAGS); - if (size > 0) { - implicitHeaderMode(); + if (size > 0) { + implicitHeaderMode(); - writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); - } else { - explicitHeaderMode(); - } + writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); + } else { + explicitHeaderMode(); + } - // clear IRQ's - writeRegister(REG_IRQ_FLAGS, irqFlags); + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, irqFlags); - if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { - // received a packet - _packetIndex = 0; + if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { + // received a packet + _packetIndex = 0; - // read packet length - if (_implicitHeaderMode) { - _available = readRegister(REG_PAYLOAD_LENGTH); - } else { - _available = readRegister(REG_RX_NB_BYTES); - } + // read packet length + if (_implicitHeaderMode) { + _available = readRegister(REG_PAYLOAD_LENGTH); + } else { + _available = readRegister(REG_RX_NB_BYTES); + } - // set FIFO address to current RX address - writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); + // set FIFO address to current RX address + writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); - // put in standby mode - idle(); - } else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { - // not currently in RX mode + // put in standby mode + idle(); + } else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { + // not currently in RX mode - // reset FIFO address - resetFifo(); + // reset FIFO address + resetFifo(); - // put in single RX mode - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); - } + // put in single RX mode + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); + } - return _available; + return _available; } int LoRaClass::packetRssi() { - return readRegister(REG_PKT_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); + return readRegister(REG_PKT_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); } float LoRaClass::packetSnr() { - return (int8_t)readRegister(REG_PKT_SNR_VALUE) * 0.25f; + return (int8_t)readRegister(REG_PKT_SNR_VALUE) * 0.25f; } long LoRaClass::packetFrequencyError() { - int32_t freqError = 0; - freqError = static_cast(readRegister(REG_FREQ_ERROR_MSB) & B111); - freqError <<= 8L; - freqError += static_cast(readRegister(REG_FREQ_ERROR_MID)); - freqError <<= 8L; - freqError += static_cast(readRegister(REG_FREQ_ERROR_LSB)); + int32_t freqError = 0; + freqError = static_cast(readRegister(REG_FREQ_ERROR_MSB) & B111); + freqError <<= 8L; + freqError += static_cast(readRegister(REG_FREQ_ERROR_MID)); + freqError <<= 8L; + freqError += static_cast(readRegister(REG_FREQ_ERROR_LSB)); - if (readRegister(REG_FREQ_ERROR_MSB) & B1000) { // Sign bit is on - freqError -= 524288; // B1000'0000'0000'0000'0000 - } + if (readRegister(REG_FREQ_ERROR_MSB) & B1000) { // Sign bit is on + freqError -= 524288; // B1000'0000'0000'0000'0000 + } - const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14) - const float fError = ((static_cast(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); // p. 37 + const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14) + const float fError = ((static_cast(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); // p. 37 - return static_cast(fError); + return static_cast(fError); } int LoRaClass::rssi() { - return readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); + return readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); } size_t LoRaClass::write(uint8_t byte) { - return write(&byte, sizeof(byte)); + return write(&byte, sizeof(byte)); } size_t LoRaClass::write(const uint8_t *buffer, size_t size) { - uint8_t currentLength = readRegister(REG_PAYLOAD_LENGTH); + uint8_t currentLength = readRegister(REG_PAYLOAD_LENGTH); - // check size - if ((size + currentLength) > MAX_PKT_LENGTH) { - size = MAX_PKT_LENGTH - currentLength; - } + // check size + if ((size + currentLength) > MAX_PKT_LENGTH) { + size = MAX_PKT_LENGTH - currentLength; + } - // write data - for (uint8_t i = 0; i < size; i++) { - writeRegister(REG_FIFO, buffer[i]); - } + // write data + for (uint8_t i = 0; i < size; i++) { + writeRegister(REG_FIFO, buffer[i]); + } - // update length - writeRegister(REG_PAYLOAD_LENGTH, currentLength + size); + // update length + writeRegister(REG_PAYLOAD_LENGTH, currentLength + size); - return size; + return size; } int LoRaClass::available() { - if (_available > _packetIndex) - return _available - _packetIndex; - return 0; - // return (readRegister(REG_RX_NB_BYTES) - _packetIndex); + if (_available > _packetIndex) + return _available - _packetIndex; + return 0; + // return (readRegister(REG_RX_NB_BYTES) - _packetIndex); } int LoRaClass::read() { - if (!available()) { - return -1; - } + if (!available()) { + return -1; + } - _packetIndex++; + _packetIndex++; - return readRegister(REG_FIFO); + return readRegister(REG_FIFO); } int LoRaClass::peek() { - if (!available()) { - return -1; - } + if (!available()) { + return -1; + } - // store current FIFO address - uint8_t currentAddress = readRegister(REG_FIFO_ADDR_PTR); + // store current FIFO address + uint8_t currentAddress = readRegister(REG_FIFO_ADDR_PTR); - // read - uint8_t b = readRegister(REG_FIFO); + // read + uint8_t b = readRegister(REG_FIFO); - // restore FIFO address - writeRegister(REG_FIFO_ADDR_PTR, currentAddress); + // restore FIFO address + writeRegister(REG_FIFO_ADDR_PTR, currentAddress); - return b; + return b; } void LoRaClass::flush() @@ -357,7 +357,7 @@ void LoRaClass::flush() void LoRaClass::onReceive(void(*callback)(uint8_t)) { - _onReceive = callback; + _onReceive = callback; // if (callback) { // pinMode(_dio0, INPUT); @@ -375,7 +375,7 @@ void LoRaClass::onReceive(void(*callback)(uint8_t)) void LoRaClass::onTxDone(void(*callback)()) { - _onTxDone = callback; + _onTxDone = callback; // if (callback) { // pinMode(_dio0, INPUT); @@ -393,392 +393,392 @@ void LoRaClass::onTxDone(void(*callback)()) void LoRaClass::continuousRx(uint8_t size) { - // wait for any existing transmission to complete - while (_transmitting) - yield(); + // wait for any existing transmission to complete + while (_transmitting) + yield(); - writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE + writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE - if (size > 0) { - implicitHeaderMode(); + if (size > 0) { + implicitHeaderMode(); - writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); - } else { - explicitHeaderMode(); - } + writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); + } else { + explicitHeaderMode(); + } - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); } void LoRaClass::singleRx() { - if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { - // not currently in RX mode + if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { + // not currently in RX mode - // wait for any existing transmission to complete - while (_transmitting) - yield(); + // wait for any existing transmission to complete + while (_transmitting) + yield(); - // reset FIFO address - resetFifo(); + // reset FIFO address + resetFifo(); - writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE + writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE - // put in single RX mode - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); - } + // put in single RX mode + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); + } } void LoRaClass::idle() { - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY); + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY); } void LoRaClass::sleep() { - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); } void LoRaClass::setTxPower(uint8_t level, uint8_t outputPin) { - if (PA_OUTPUT_RFO_PIN == outputPin) { - // RFO - if (level < 0) { - level = 0; - } else if (level > 14) { - level = 14; - } - - writeRegister(REG_PA_CONFIG, 0x70 | level); - } else { - // PA BOOST - if (level > 17) { - if (level > 20) { - level = 20; - } - - // subtract 3 from level, so 18 - 20 maps to 15 - 17 - level -= 3; + if (PA_OUTPUT_RFO_PIN == outputPin) { + // RFO + if (level < 0) { + level = 0; + } else if (level > 14) { + level = 14; + } - // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) - writeRegister(REG_PA_DAC, 0x87); - setOCP(140); + writeRegister(REG_PA_CONFIG, 0x70 | level); } else { - if (level < 2) { - level = 2; - } - //Default value PA_HF/LF or +17dBm - writeRegister(REG_PA_DAC, 0x84); - setOCP(100); + // PA BOOST + if (level > 17) { + if (level > 20) { + level = 20; + } + + // subtract 3 from level, so 18 - 20 maps to 15 - 17 + level -= 3; + + // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) + writeRegister(REG_PA_DAC, 0x87); + setOCP(140); + } else { + if (level < 2) { + level = 2; + } + //Default value PA_HF/LF or +17dBm + writeRegister(REG_PA_DAC, 0x84); + setOCP(100); + } + + writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)); } - - writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)); - } } void LoRaClass::setFrequency(long frequency) { - _frequency = frequency; + _frequency = frequency; - uint64_t frf = ((uint64_t)frequency << 19) / 32000000; + uint64_t frf = ((uint64_t)frequency << 19) / 32000000; - writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16)); - writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8)); - writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); + writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16)); + writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8)); + writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); } uint8_t LoRaClass::getSpreadingFactor() { - return readRegister(REG_MODEM_CONFIG_2) >> 4; + return readRegister(REG_MODEM_CONFIG_2) >> 4; } void LoRaClass::setSpreadingFactor(uint8_t sf) { - if (sf < 6) { - sf = 6; - } else if (sf > 12) { - sf = 12; - } + if (sf < 6) { + sf = 6; + } else if (sf > 12) { + sf = 12; + } - if (sf == 6) { - writeRegister(REG_DETECTION_OPTIMIZE, 0xc5); - writeRegister(REG_DETECTION_THRESHOLD, 0x0c); - } else { - writeRegister(REG_DETECTION_OPTIMIZE, 0xc3); - writeRegister(REG_DETECTION_THRESHOLD, 0x0a); - } + if (sf == 6) { + writeRegister(REG_DETECTION_OPTIMIZE, 0xc5); + writeRegister(REG_DETECTION_THRESHOLD, 0x0c); + } else { + writeRegister(REG_DETECTION_OPTIMIZE, 0xc3); + writeRegister(REG_DETECTION_THRESHOLD, 0x0a); + } - writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); - setLdoFlag(); + writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); + setLdoFlag(); } long LoRaClass::getSignalBandwidth() { - uint8_t bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); - - switch (bw) { - case 0: return 7.8E3; - case 1: return 10.4E3; - case 2: return 15.6E3; - case 3: return 20.8E3; - case 4: return 31.25E3; - case 5: return 41.7E3; - case 6: return 62.5E3; - case 7: return 125E3; - case 8: return 250E3; - case 9: return 500E3; - } + uint8_t bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); + + switch (bw) { + case 0: return 7.8E3; + case 1: return 10.4E3; + case 2: return 15.6E3; + case 3: return 20.8E3; + case 4: return 31.25E3; + case 5: return 41.7E3; + case 6: return 62.5E3; + case 7: return 125E3; + case 8: return 250E3; + case 9: return 500E3; + } - return -1; + return -1; } void LoRaClass::setSignalBandwidth(long sbw) { - uint8_t bw; - - if (sbw <= 7.8E3) { - bw = 0; - } else if (sbw <= 10.4E3) { - bw = 1; - } else if (sbw <= 15.6E3) { - bw = 2; - } else if (sbw <= 20.8E3) { - bw = 3; - } else if (sbw <= 31.25E3) { - bw = 4; - } else if (sbw <= 41.7E3) { - bw = 5; - } else if (sbw <= 62.5E3) { - bw = 6; - } else if (sbw <= 125E3) { - bw = 7; - } else if (sbw <= 250E3) { - bw = 8; - } else /*if (sbw <= 250E3)*/ { - bw = 9; - } - - writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)); - setLdoFlag(); + uint8_t bw; + + if (sbw <= 7.8E3) { + bw = 0; + } else if (sbw <= 10.4E3) { + bw = 1; + } else if (sbw <= 15.6E3) { + bw = 2; + } else if (sbw <= 20.8E3) { + bw = 3; + } else if (sbw <= 31.25E3) { + bw = 4; + } else if (sbw <= 41.7E3) { + bw = 5; + } else if (sbw <= 62.5E3) { + bw = 6; + } else if (sbw <= 125E3) { + bw = 7; + } else if (sbw <= 250E3) { + bw = 8; + } else /*if (sbw <= 250E3)*/ { + bw = 9; + } + + writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)); + setLdoFlag(); } void LoRaClass::setLdoFlag() { - // Section 4.1.1.5 - float symbolDuration = 1000.0f / ((float)getSignalBandwidth() / (1u << getSpreadingFactor())); - Serial.print("symbolDuration: "); Serial.println(symbolDuration); + // Section 4.1.1.5 + float symbolDuration = 1000.0f / ((float)getSignalBandwidth() / (1u << getSpreadingFactor())); + Serial.print("symbolDuration: "); Serial.println(symbolDuration); - // Section 4.1.1.6 - bool ldoOn = symbolDuration > 16.0f; + // Section 4.1.1.6 + bool ldoOn = symbolDuration > 16.0f; - uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); - bitWrite(config3, 3, ldoOn); - writeRegister(REG_MODEM_CONFIG_3, config3); + uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); + bitWrite(config3, 3, ldoOn); + writeRegister(REG_MODEM_CONFIG_3, config3); } void LoRaClass::setCodingRate4(uint8_t denominator) { - if (denominator < 5) { - denominator = 5; - } else if (denominator > 8) { - denominator = 8; - } + if (denominator < 5) { + denominator = 5; + } else if (denominator > 8) { + denominator = 8; + } - uint8_t cr = denominator - 4; + uint8_t cr = denominator - 4; - writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); + writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); } void LoRaClass::setPreambleLength(uint16_t length) { - writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); - writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); + writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); + writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); } void LoRaClass::setSyncWord(uint8_t sw) { - writeRegister(REG_SYNC_WORD, sw); + writeRegister(REG_SYNC_WORD, sw); } void LoRaClass::enableCrc() { - writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04); + writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04); } void LoRaClass::disableCrc() { - writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); + writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); } void LoRaClass::enableInvertIQ() { - writeRegister(REG_INVERTIQ, 0x66); - writeRegister(REG_INVERTIQ2, 0x19); + writeRegister(REG_INVERTIQ, 0x66); + writeRegister(REG_INVERTIQ2, 0x19); } void LoRaClass::disableInvertIQ() { - writeRegister(REG_INVERTIQ, 0x27); - writeRegister(REG_INVERTIQ2, 0x1d); + writeRegister(REG_INVERTIQ, 0x27); + writeRegister(REG_INVERTIQ2, 0x1d); } void LoRaClass::setOCP(uint8_t mA) { - uint8_t ocpTrim = 27; + uint8_t ocpTrim = 27; - if (mA <= 120) { - ocpTrim = (mA - 45) / 5; - } else if (mA <=240) { - ocpTrim = (mA + 30) / 10; - } + if (mA <= 120) { + ocpTrim = (mA - 45) / 5; + } else if (mA <=240) { + ocpTrim = (mA + 30) / 10; + } - writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim)); + writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim)); } void LoRaClass::setGain(uint8_t gain) { - // check allowed range - if (gain > 6) { - gain = 6; - } - - // set to standby - idle(); - - // set gain - if (gain == 0) { - // if gain = 0, enable AGC - writeRegister(REG_MODEM_CONFIG_3, 0x04); // TODO use bit set - } else { - // disable AGC - writeRegister(REG_MODEM_CONFIG_3, 0x00); // TODO use bit set - - // clear Gain and set LNA boost - writeRegister(REG_LNA, 0x03); - + // check allowed range + if (gain > 6) { + gain = 6; + } + + // set to standby + idle(); + // set gain - writeRegister(REG_LNA, readRegister(REG_LNA) | (gain << 5)); - } + if (gain == 0) { + // if gain = 0, enable AGC + writeRegister(REG_MODEM_CONFIG_3, 0x04); // TODO use bit set + } else { + // disable AGC + writeRegister(REG_MODEM_CONFIG_3, 0x00); // TODO use bit set + + // clear Gain and set LNA boost + writeRegister(REG_LNA, 0x03); + + // set gain + writeRegister(REG_LNA, readRegister(REG_LNA) | (gain << 5)); + } } uint8_t LoRaClass::random() { - return readRegister(REG_RSSI_WIDEBAND); + return readRegister(REG_RSSI_WIDEBAND); } void LoRaClass::setPins(uint8_t ss, uint8_t reset, uint8_t dio0) { - _ss = ss; - _reset = reset; - _dio0 = dio0; + _ss = ss; + _reset = reset; + _dio0 = dio0; } void LoRaClass::setSPI(SPIClass& spi) { - _spi = &spi; + _spi = &spi; } void LoRaClass::setSPIFrequency(uint32_t frequency) { - _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); + _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); } void LoRaClass::dumpRegisters(Stream& out) { - for (uint8_t i = 0; i < 128; i++) { - out.print("0x"); - out.print(i, HEX); - out.print(": 0x"); - out.println(readRegister(i), HEX); - } + for (uint8_t i = 0; i < 128; i++) { + out.print("0x"); + out.print(i, HEX); + out.print(": 0x"); + out.println(readRegister(i), HEX); + } } void LoRaClass::explicitHeaderMode() { - _implicitHeaderMode = 0; + _implicitHeaderMode = 0; - writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe); + writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe); } void LoRaClass::implicitHeaderMode() { - _implicitHeaderMode = 1; + _implicitHeaderMode = 1; - writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01); + writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01); } void LoRaClass::handleDio0Rise() { - uint8_t irqFlags = readRegister(REG_IRQ_FLAGS); - // Serial.print("---- IRQ: "); Serial.println(irqFlags, BIN); + uint8_t irqFlags = readRegister(REG_IRQ_FLAGS); + // Serial.print("---- IRQ: "); Serial.println(irqFlags, BIN); - // clear IRQ's - writeRegister(REG_IRQ_FLAGS, irqFlags); + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, irqFlags); - if (irqFlags & IRQ_TX_DONE_MASK) { - _transmitting = false; - if (_onTxDone) { - _onTxDone(); + if (irqFlags & IRQ_TX_DONE_MASK) { + _transmitting = false; + if (_onTxDone) { + _onTxDone(); + } } - } - else if ((irqFlags & IRQ_RX_DONE_MASK) && !(irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK)) { - // received a packet - _packetIndex = 0; + else if ((irqFlags & IRQ_RX_DONE_MASK) && !(irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK)) { + // received a packet + _packetIndex = 0; - // read packet length - _available = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH) : readRegister(REG_RX_NB_BYTES); + // read packet length + _available = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH) : readRegister(REG_RX_NB_BYTES); - // set FIFO address to current RX address - writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); + // set FIFO address to current RX address + writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); - if (_onReceive) { - _onReceive(_available); + if (_onReceive) { + _onReceive(_available); + } } - } } void LoRaClass::resetFifo() { - // reset FIFO address - writeRegister(REG_FIFO_ADDR_PTR, 0); - _available = 0; - _packetIndex = 0; + // reset FIFO address + writeRegister(REG_FIFO_ADDR_PTR, 0); + _available = 0; + _packetIndex = 0; } uint8_t LoRaClass::readRegister(uint8_t address) { - return singleTransfer(address & 0x7f, 0x00); + return singleTransfer(address & 0x7f, 0x00); } void LoRaClass::writeRegister(uint8_t address, uint8_t value) { - singleTransfer(address | 0x80, value); + singleTransfer(address | 0x80, value); } uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value) { - uint8_t response; + uint8_t response; - digitalWrite(_ss, LOW); + digitalWrite(_ss, LOW); - _spi->beginTransaction(_spiSettings); - _spi->transfer(address); - response = _spi->transfer(value); - _spi->endTransaction(); + _spi->beginTransaction(_spiSettings); + _spi->transfer(address); + response = _spi->transfer(value); + _spi->endTransaction(); - digitalWrite(_ss, HIGH); + digitalWrite(_ss, HIGH); - return response; + return response; } void LoRaClass::debug() { - Serial.print("mode: "); Serial.print(readRegister(REG_OP_MODE), BIN); Serial.print(" status: "); Serial.println(readRegister(0x18), BIN); + Serial.print("mode: "); Serial.print(readRegister(REG_OP_MODE), BIN); Serial.print(" status: "); Serial.println(readRegister(0x18), BIN); } ISR_PREFIX void LoRaClass::onDio0Rise() { - LoRa.handleDio0Rise(); + LoRa.handleDio0Rise(); } LoRaClass LoRa; diff --git a/src/LoRa.h b/src/LoRa.h index 18e298d..b0b2fa9 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -18,100 +18,100 @@ class LoRaClass : public Stream { public: - LoRaClass(); - - bool begin(long frequency); - void end(); - - bool beginPacket(int implicitHeader = false); - bool endPacket(bool async = false); - - uint8_t parsePacket(uint8_t size = 0); - int packetRssi(); - float packetSnr(); - long packetFrequencyError(); - - int rssi(); - - // from Print - virtual size_t write(uint8_t byte); - virtual size_t write(const uint8_t *buffer, size_t size); - - // from Stream - virtual int available(); - virtual int read(); - virtual int peek(); - virtual void flush(); - - void onReceive(void(*callback)(uint8_t)); - void onTxDone(void(*callback)()); - - void continuousRx(uint8_t size = 0); - void singleRx(); - void idle(); - void sleep(); - - void setTxPower(uint8_t level, uint8_t outputPin = PA_OUTPUT_PA_BOOST_PIN); - void setFrequency(long frequency); - void setSpreadingFactor(uint8_t sf); - void setSignalBandwidth(long sbw); - void setCodingRate4(uint8_t denominator); - void setPreambleLength(uint16_t length); - void setSyncWord(uint8_t sw); - void enableCrc(); - void disableCrc(); - void enableInvertIQ(); - void disableInvertIQ(); - - void setOCP(uint8_t mA); // Over Current Protection control - - void setGain(uint8_t gain); // Set LNA gain - - // deprecated - void crc() { enableCrc(); } - void noCrc() { disableCrc(); } - - uint8_t random(); - - void setPins(uint8_t ss = LORA_DEFAULT_SS_PIN, uint8_t reset = LORA_DEFAULT_RESET_PIN, uint8_t dio0 = LORA_DEFAULT_DIO0_PIN); - void setSPI(SPIClass& spi); - void setSPIFrequency(uint32_t frequency); - - void dumpRegisters(Stream& out); - void debug(); + LoRaClass(); + + bool begin(long frequency); + void end(); + + bool beginPacket(int implicitHeader = false); + bool endPacket(bool async = false); + + uint8_t parsePacket(uint8_t size = 0); + int packetRssi(); + float packetSnr(); + long packetFrequencyError(); + + int rssi(); + + // from Print + virtual size_t write(uint8_t byte); + virtual size_t write(const uint8_t *buffer, size_t size); + + // from Stream + virtual int available(); + virtual int read(); + virtual int peek(); + virtual void flush(); + + void onReceive(void(*callback)(uint8_t)); + void onTxDone(void(*callback)()); + + void continuousRx(uint8_t size = 0); + void singleRx(); + void idle(); + void sleep(); + + void setTxPower(uint8_t level, uint8_t outputPin = PA_OUTPUT_PA_BOOST_PIN); + void setFrequency(long frequency); + void setSpreadingFactor(uint8_t sf); + void setSignalBandwidth(long sbw); + void setCodingRate4(uint8_t denominator); + void setPreambleLength(uint16_t length); + void setSyncWord(uint8_t sw); + void enableCrc(); + void disableCrc(); + void enableInvertIQ(); + void disableInvertIQ(); + + void setOCP(uint8_t mA); // Over Current Protection control + + void setGain(uint8_t gain); // Set LNA gain + + // deprecated + void crc() { enableCrc(); } + void noCrc() { disableCrc(); } + + uint8_t random(); + + void setPins(uint8_t ss = LORA_DEFAULT_SS_PIN, uint8_t reset = LORA_DEFAULT_RESET_PIN, uint8_t dio0 = LORA_DEFAULT_DIO0_PIN); + void setSPI(SPIClass& spi); + void setSPIFrequency(uint32_t frequency); + + void dumpRegisters(Stream& out); + void debug(); private: - void explicitHeaderMode(); - void implicitHeaderMode(); + void explicitHeaderMode(); + void implicitHeaderMode(); - void handleDio0Rise(); - // bool isTransmitting(); - void resetFifo(); + void handleDio0Rise(); + // bool isTransmitting(); + void resetFifo(); - uint8_t getSpreadingFactor(); - long getSignalBandwidth(); + uint8_t getSpreadingFactor(); + long getSignalBandwidth(); - void setLdoFlag(); + void setLdoFlag(); - uint8_t readRegister(uint8_t address); - void writeRegister(uint8_t address, uint8_t value); - uint8_t singleTransfer(uint8_t address, uint8_t value); + uint8_t readRegister(uint8_t address); + void writeRegister(uint8_t address, uint8_t value); + uint8_t singleTransfer(uint8_t address, uint8_t value); - static void onDio0Rise(); + static void onDio0Rise(); private: - SPISettings _spiSettings; - SPIClass* _spi; - uint8_t _ss; - uint8_t _reset; - uint8_t _dio0; - long _frequency; - bool _implicitHeaderMode; - volatile bool _transmitting; - volatile uint8_t _packetIndex; - volatile uint8_t _available; - void (*_onReceive)(uint8_t); - void (*_onTxDone)(); + SPISettings _spiSettings; + SPIClass* _spi; + uint8_t _ss; + uint8_t _reset; + uint8_t _dio0; + long _frequency; + bool _implicitHeaderMode; + volatile bool _transmitting; + volatile uint8_t _packetIndex; + volatile uint8_t _available; + void (*_onReceive)(uint8_t); + void (*_onTxDone)(); }; extern LoRaClass LoRa; From 6eeb3fccf12c6de9153e68258f7fcef3fd1e065d Mon Sep 17 00:00:00 2001 From: Matt Mason Date: Sun, 18 Aug 2024 22:05:06 -0500 Subject: [PATCH 3/9] Reorganize & Reformat --- src/LoRa.cpp | 714 +++++++++++++++++++++------------------------------ src/LoRa.h | 94 ++++--- 2 files changed, 344 insertions(+), 464 deletions(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 9cbfef0..10f5c80 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -41,26 +41,27 @@ #define REG_PA_DAC 0x4d // modes -#define MODE_LONG_RANGE_MODE 0x80 -#define MODE_SLEEP 0x00 -#define MODE_STDBY 0x01 -#define MODE_TX 0x03 -#define MODE_RX_CONTINUOUS 0x05 -#define MODE_RX_SINGLE 0x06 +#define MODE_LONG_RANGE_MODE 0x80 +#define MODE_SLEEP 0x00 +#define MODE_STDBY 0x01 +#define MODE_TX 0x03 +#define MODE_RX_CONTINUOUS 0x05 +#define MODE_RX_SINGLE 0x06 // PA config -#define PA_BOOST 0x80 +#define PA_BOOST 0x80 // IRQ masks #define IRQ_TX_DONE_MASK 0x08 #define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 #define IRQ_RX_DONE_MASK 0x40 -#define RF_MID_BAND_THRESHOLD 525E6 -#define RSSI_OFFSET_HF_PORT 157 -#define RSSI_OFFSET_LF_PORT 164 +// RF +#define RF_MID_BAND_THRESHOLD 525E6 +#define RSSI_OFFSET_HF_PORT 157 +#define RSSI_OFFSET_LF_PORT 164 -#define MAX_PKT_LENGTH 255 +#define MAX_PKT_LENGTH 255 #if (ESP8266 || ESP32) #define ISR_PREFIX ICACHE_RAM_ATTR @@ -68,6 +69,10 @@ #define ISR_PREFIX #endif +//****************************************************************************** +// Public Functions +//****************************************************************************** + LoRaClass::LoRaClass() : _spiSettings(LORA_DEFAULT_SPI_FREQUENCY, MSBFIRST, SPI_MODE0), _spi(&LORA_DEFAULT_SPI), @@ -77,22 +82,36 @@ LoRaClass::LoRaClass() : _transmitting(false), _packetIndex(0), _available(0), - _onReceive(NULL), + _onRxDone(NULL), _onTxDone(NULL) { // overide Stream timeout value setTimeout(0); } +void LoRaClass::setPins(uint8_t ss, uint8_t reset, uint8_t dio0) +{ + _ss = ss; + _reset = reset; + _dio0 = dio0; +} + +void LoRaClass::setSPIFrequency(uint32_t frequency) +{ + _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); +} + bool LoRaClass::begin(long frequency) { // setup pins pinMode(_ss, OUTPUT); pinMode(_dio0, INPUT); + // set SS high digitalWrite(_ss, HIGH); - if (_reset != -1) { + if (_reset != -1) + { pinMode(_reset, OUTPUT); // perform reset @@ -151,244 +170,183 @@ void LoRaClass::end() _spi->end(); } -bool LoRaClass::beginPacket(int implicitHeader) +void LoRaClass::setTxPower(uint8_t level, uint8_t outputPin) { - if (_transmitting) { - return 0; - } - - // put in standby mode - idle(); + if (PA_OUTPUT_RFO_PIN == outputPin) + { + if (level > 14) + level = 14; - if (implicitHeader) { - implicitHeaderMode(); - } else { - explicitHeaderMode(); + writeRegister(REG_PA_CONFIG, 0x70 | level); } + else // PA BOOST + { + if (level > 17) + { + if (level > 20) + level = 20; - // reset FIFO address and paload length - resetFifo(); - writeRegister(REG_PAYLOAD_LENGTH, 0); - - return 1; -} - -bool LoRaClass::endPacket(bool async) -{ - - // if ((async) || (_onTxDone)) - writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE + // subtract 3 from level, so 18 - 20 maps to 15 - 17 + level -= 3; - // put in TX mode - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); - _transmitting = true; + // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) + writeRegister(REG_PA_DAC, 0x87); + setOCP(140); + } + else // level <= 17 + { + if (level < 2) + level = 2; - if (!async) { - // wait for TX done - while (_transmitting) {//(readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { - yield(); + //Default value PA_HF/LF or +17dBm + writeRegister(REG_PA_DAC, 0x84); + setOCP(100); } - // clear IRQ's - // writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); + writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)); } - - return 1; } -// bool LoRaClass::isTransmitting() -// { -// if ((readRegister(REG_OP_MODE) & MODE_TX) == MODE_TX) { -// return true; -// } +void LoRaClass::setFrequency(long frequency) +{ + _frequency = frequency; -// if (readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) { -// // clear IRQ's -// writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); -// } + uint64_t frf = ((uint64_t)frequency << 19) / 32000000; -// return false; -// } + writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16)); + writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8)); + writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); +} -uint8_t LoRaClass::parsePacket(uint8_t size) +void LoRaClass::setSpreadingFactor(uint8_t sf) { - uint8_t packetLength = 0; - uint8_t irqFlags = readRegister(REG_IRQ_FLAGS); - - if (size > 0) { - implicitHeaderMode(); + if (sf < 6) + sf = 6; + else if (sf > 12) + sf = 12; - writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); - } else { - explicitHeaderMode(); + if (sf == 6) + { + writeRegister(REG_DETECTION_OPTIMIZE, 0xc5); + writeRegister(REG_DETECTION_THRESHOLD, 0x0c); } - - // clear IRQ's - writeRegister(REG_IRQ_FLAGS, irqFlags); - - if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { - // received a packet - _packetIndex = 0; - - // read packet length - if (_implicitHeaderMode) { - _available = readRegister(REG_PAYLOAD_LENGTH); - } else { - _available = readRegister(REG_RX_NB_BYTES); - } - - // set FIFO address to current RX address - writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); - - // put in standby mode - idle(); - } else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { - // not currently in RX mode - - // reset FIFO address - resetFifo(); - - // put in single RX mode - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); + else + { + writeRegister(REG_DETECTION_OPTIMIZE, 0xc3); + writeRegister(REG_DETECTION_THRESHOLD, 0x0a); } - return _available; + writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); + setLdoFlag(); } -int LoRaClass::packetRssi() +void LoRaClass::setSignalBandwidth(long sbw) { - return readRegister(REG_PKT_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); -} + uint8_t bw; -float LoRaClass::packetSnr() -{ - return (int8_t)readRegister(REG_PKT_SNR_VALUE) * 0.25f; + if (sbw <= 7.8E3) + bw = 0; + else if (sbw <= 10.4E3) + bw = 1; + else if (sbw <= 15.6E3) + bw = 2; + else if (sbw <= 20.8E3) + bw = 3; + else if (sbw <= 31.25E3) + bw = 4; + else if (sbw <= 41.7E3) + bw = 5; + else if (sbw <= 62.5E3) + bw = 6; + else if (sbw <= 125E3) + bw = 7; + else if (sbw <= 250E3) + bw = 8; + else // 500E3 + bw = 9; + + writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)); + setLdoFlag(); } -long LoRaClass::packetFrequencyError() +void LoRaClass::setCodingRate4(uint8_t denominator) { - int32_t freqError = 0; - freqError = static_cast(readRegister(REG_FREQ_ERROR_MSB) & B111); - freqError <<= 8L; - freqError += static_cast(readRegister(REG_FREQ_ERROR_MID)); - freqError <<= 8L; - freqError += static_cast(readRegister(REG_FREQ_ERROR_LSB)); - - if (readRegister(REG_FREQ_ERROR_MSB) & B1000) { // Sign bit is on - freqError -= 524288; // B1000'0000'0000'0000'0000 - } + if (denominator < 5) + denominator = 5; + else if (denominator > 8) + denominator = 8; - const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14) - const float fError = ((static_cast(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); // p. 37 + uint8_t cr = denominator - 4; - return static_cast(fError); + writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); } -int LoRaClass::rssi() +void LoRaClass::setPreambleLength(uint16_t length) { - return readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); + writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); + writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); } -size_t LoRaClass::write(uint8_t byte) +void LoRaClass::setSyncWord(uint8_t sw) { - return write(&byte, sizeof(byte)); + writeRegister(REG_SYNC_WORD, sw); } -size_t LoRaClass::write(const uint8_t *buffer, size_t size) +void LoRaClass::enableCrc() { - uint8_t currentLength = readRegister(REG_PAYLOAD_LENGTH); - - // check size - if ((size + currentLength) > MAX_PKT_LENGTH) { - size = MAX_PKT_LENGTH - currentLength; - } - - // write data - for (uint8_t i = 0; i < size; i++) { - writeRegister(REG_FIFO, buffer[i]); - } - - // update length - writeRegister(REG_PAYLOAD_LENGTH, currentLength + size); - - return size; + writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04); } -int LoRaClass::available() +void LoRaClass::disableCrc() { - if (_available > _packetIndex) - return _available - _packetIndex; - return 0; - // return (readRegister(REG_RX_NB_BYTES) - _packetIndex); + writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); } -int LoRaClass::read() +void LoRaClass::enableInvertIQ() { - if (!available()) { - return -1; - } - - _packetIndex++; - - return readRegister(REG_FIFO); + writeRegister(REG_INVERTIQ, 0x66); + writeRegister(REG_INVERTIQ2, 0x19); } -int LoRaClass::peek() +void LoRaClass::disableInvertIQ() { - if (!available()) { - return -1; - } - - // store current FIFO address - uint8_t currentAddress = readRegister(REG_FIFO_ADDR_PTR); - - // read - uint8_t b = readRegister(REG_FIFO); - - // restore FIFO address - writeRegister(REG_FIFO_ADDR_PTR, currentAddress); - - return b; + writeRegister(REG_INVERTIQ, 0x27); + writeRegister(REG_INVERTIQ2, 0x1d); } -void LoRaClass::flush() +void LoRaClass::setOCP(uint8_t mA) { -} + uint8_t ocpTrim = 27; -void LoRaClass::onReceive(void(*callback)(uint8_t)) -{ - _onReceive = callback; + if (mA <= 120) + ocpTrim = (mA - 45) / 5; + else if (mA <=240) + ocpTrim = (mA + 30) / 10; -// if (callback) { -// pinMode(_dio0, INPUT); -// #ifdef SPI_HAS_NOTUSINGINTERRUPT -// SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); -// #endif -// attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); -// } else { -// detachInterrupt(digitalPinToInterrupt(_dio0)); -// #ifdef SPI_HAS_NOTUSINGINTERRUPT -// SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); -// #endif -// } + writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim)); } -void LoRaClass::onTxDone(void(*callback)()) +void LoRaClass::setGain(uint8_t gain) { - _onTxDone = callback; + if (gain > 6) + gain = 6; -// if (callback) { -// pinMode(_dio0, INPUT); -// #ifdef SPI_HAS_NOTUSINGINTERRUPT -// SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); -// #endif -// attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); -// } else { -// detachInterrupt(digitalPinToInterrupt(_dio0)); -// #ifdef SPI_HAS_NOTUSINGINTERRUPT -// SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); -// #endif -// } + // set to standby + idle(); + + if (gain == 0) + { + // if gain = 0, enable AGC + writeRegister(REG_MODEM_CONFIG_3, 0x04); // TODO use bit set + } + else + { + // disable AGC + writeRegister(REG_MODEM_CONFIG_3, 0x00); // TODO use bit set + + // set gain and LNA boost + writeRegister(REG_LNA, (gain << 5) | 0x03); + } } void LoRaClass::continuousRx(uint8_t size) @@ -399,22 +357,21 @@ void LoRaClass::continuousRx(uint8_t size) writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE - if (size > 0) { + if (size > 0) + { implicitHeaderMode(); - writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); - } else { - explicitHeaderMode(); } + else + explicitHeaderMode(); writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); } void LoRaClass::singleRx() { - if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { - // not currently in RX mode - + if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) + { // wait for any existing transmission to complete while (_transmitting) yield(); @@ -439,226 +396,126 @@ void LoRaClass::sleep() writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); } -void LoRaClass::setTxPower(uint8_t level, uint8_t outputPin) +void LoRaClass::beginPacket(int implicitHeader) { - if (PA_OUTPUT_RFO_PIN == outputPin) { - // RFO - if (level < 0) { - level = 0; - } else if (level > 14) { - level = 14; - } - - writeRegister(REG_PA_CONFIG, 0x70 | level); - } else { - // PA BOOST - if (level > 17) { - if (level > 20) { - level = 20; - } + // wait for any existing transmission to complete + while (_transmitting) + yield(); - // subtract 3 from level, so 18 - 20 maps to 15 - 17 - level -= 3; + // put in standby mode + idle(); - // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) - writeRegister(REG_PA_DAC, 0x87); - setOCP(140); - } else { - if (level < 2) { - level = 2; - } - //Default value PA_HF/LF or +17dBm - writeRegister(REG_PA_DAC, 0x84); - setOCP(100); - } + if (implicitHeader) + implicitHeaderMode(); + else + explicitHeaderMode(); - writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)); - } + // reset FIFO address and paload length + resetFifo(); + writeRegister(REG_PAYLOAD_LENGTH, 0); } -void LoRaClass::setFrequency(long frequency) +size_t LoRaClass::write(uint8_t byte) { - _frequency = frequency; - - uint64_t frf = ((uint64_t)frequency << 19) / 32000000; - - writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16)); - writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8)); - writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); + return write(&byte, sizeof(byte)); } -uint8_t LoRaClass::getSpreadingFactor() +size_t LoRaClass::write(const uint8_t *buffer, size_t size) { - return readRegister(REG_MODEM_CONFIG_2) >> 4; -} + uint8_t currentLength = readRegister(REG_PAYLOAD_LENGTH); -void LoRaClass::setSpreadingFactor(uint8_t sf) -{ - if (sf < 6) { - sf = 6; - } else if (sf > 12) { - sf = 12; - } + // check size + if ((size + currentLength) > MAX_PKT_LENGTH) + size = MAX_PKT_LENGTH - currentLength; - if (sf == 6) { - writeRegister(REG_DETECTION_OPTIMIZE, 0xc5); - writeRegister(REG_DETECTION_THRESHOLD, 0x0c); - } else { - writeRegister(REG_DETECTION_OPTIMIZE, 0xc3); - writeRegister(REG_DETECTION_THRESHOLD, 0x0a); - } + // write data + for (uint8_t i = 0; i < size; i++) + writeRegister(REG_FIFO, buffer[i]); - writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); - setLdoFlag(); + // update length + writeRegister(REG_PAYLOAD_LENGTH, currentLength + size); + + return size; } -long LoRaClass::getSignalBandwidth() +void LoRaClass::endPacket(bool blocking) { - uint8_t bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); + writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE - switch (bw) { - case 0: return 7.8E3; - case 1: return 10.4E3; - case 2: return 15.6E3; - case 3: return 20.8E3; - case 4: return 31.25E3; - case 5: return 41.7E3; - case 6: return 62.5E3; - case 7: return 125E3; - case 8: return 250E3; - case 9: return 500E3; - } + // put in TX mode + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); + _transmitting = true; - return -1; + if (blocking) + while (_transmitting) + yield(); } -void LoRaClass::setSignalBandwidth(long sbw) +int LoRaClass::available() { - uint8_t bw; - - if (sbw <= 7.8E3) { - bw = 0; - } else if (sbw <= 10.4E3) { - bw = 1; - } else if (sbw <= 15.6E3) { - bw = 2; - } else if (sbw <= 20.8E3) { - bw = 3; - } else if (sbw <= 31.25E3) { - bw = 4; - } else if (sbw <= 41.7E3) { - bw = 5; - } else if (sbw <= 62.5E3) { - bw = 6; - } else if (sbw <= 125E3) { - bw = 7; - } else if (sbw <= 250E3) { - bw = 8; - } else /*if (sbw <= 250E3)*/ { - bw = 9; - } - - writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)); - setLdoFlag(); + if (_available > _packetIndex) + return _available - _packetIndex; + return 0; } -void LoRaClass::setLdoFlag() +int LoRaClass::read() { - // Section 4.1.1.5 - float symbolDuration = 1000.0f / ((float)getSignalBandwidth() / (1u << getSpreadingFactor())); - Serial.print("symbolDuration: "); Serial.println(symbolDuration); + if (!available()) + return -1; - // Section 4.1.1.6 - bool ldoOn = symbolDuration > 16.0f; + _packetIndex++; - uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); - bitWrite(config3, 3, ldoOn); - writeRegister(REG_MODEM_CONFIG_3, config3); + return readRegister(REG_FIFO); } -void LoRaClass::setCodingRate4(uint8_t denominator) +int LoRaClass::peek() { - if (denominator < 5) { - denominator = 5; - } else if (denominator > 8) { - denominator = 8; - } - - uint8_t cr = denominator - 4; + if (!available()) + return -1; - writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); -} + // store current FIFO address + uint8_t currentAddress = readRegister(REG_FIFO_ADDR_PTR); -void LoRaClass::setPreambleLength(uint16_t length) -{ - writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); - writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); -} + // read + uint8_t b = readRegister(REG_FIFO); -void LoRaClass::setSyncWord(uint8_t sw) -{ - writeRegister(REG_SYNC_WORD, sw); -} + // restore FIFO address + writeRegister(REG_FIFO_ADDR_PTR, currentAddress); -void LoRaClass::enableCrc() -{ - writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04); + return b; } -void LoRaClass::disableCrc() +int LoRaClass::packetRssi() { - writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); + return readRegister(REG_PKT_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); } -void LoRaClass::enableInvertIQ() +float LoRaClass::packetSnr() { - writeRegister(REG_INVERTIQ, 0x66); - writeRegister(REG_INVERTIQ2, 0x19); + return (int8_t)readRegister(REG_PKT_SNR_VALUE) * 0.25f; } -void LoRaClass::disableInvertIQ() +long LoRaClass::packetFrequencyError() { - writeRegister(REG_INVERTIQ, 0x27); - writeRegister(REG_INVERTIQ2, 0x1d); -} + int32_t freqError = 0; + freqError = static_cast(readRegister(REG_FREQ_ERROR_MSB) & B111); + freqError <<= 8L; + freqError += static_cast(readRegister(REG_FREQ_ERROR_MID)); + freqError <<= 8L; + freqError += static_cast(readRegister(REG_FREQ_ERROR_LSB)); -void LoRaClass::setOCP(uint8_t mA) -{ - uint8_t ocpTrim = 27; + if (readRegister(REG_FREQ_ERROR_MSB) & B1000) // Sign bit is on + freqError -= 524288; // B1000'0000'0000'0000'0000 - if (mA <= 120) { - ocpTrim = (mA - 45) / 5; - } else if (mA <=240) { - ocpTrim = (mA + 30) / 10; - } + const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14) + const float fError = ((static_cast(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); // p. 37 - writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim)); + return static_cast(fError); } -void LoRaClass::setGain(uint8_t gain) +int LoRaClass::rssi() { - // check allowed range - if (gain > 6) { - gain = 6; - } - - // set to standby - idle(); - - // set gain - if (gain == 0) { - // if gain = 0, enable AGC - writeRegister(REG_MODEM_CONFIG_3, 0x04); // TODO use bit set - } else { - // disable AGC - writeRegister(REG_MODEM_CONFIG_3, 0x00); // TODO use bit set - - // clear Gain and set LNA boost - writeRegister(REG_LNA, 0x03); - - // set gain - writeRegister(REG_LNA, readRegister(REG_LNA) | (gain << 5)); - } + return readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); } uint8_t LoRaClass::random() @@ -666,47 +523,90 @@ uint8_t LoRaClass::random() return readRegister(REG_RSSI_WIDEBAND); } -void LoRaClass::setPins(uint8_t ss, uint8_t reset, uint8_t dio0) +void LoRaClass::dumpRegisters(Stream& out) { - _ss = ss; - _reset = reset; - _dio0 = dio0; + for (uint8_t i = 0; i < 128; i++) + { + out.print("0x"); + out.print(i, HEX); + out.print(": 0x"); + out.println(readRegister(i), HEX); + } } -void LoRaClass::setSPI(SPIClass& spi) +void LoRaClass::debug() { - _spi = &spi; + Serial.print("mode: "); Serial.print(readRegister(REG_OP_MODE), BIN); Serial.print(" status: "); Serial.println(readRegister(0x18), BIN); } -void LoRaClass::setSPIFrequency(uint32_t frequency) +//****************************************************************************** +// Private Functions +//****************************************************************************** + +uint8_t LoRaClass::getSpreadingFactor() { - _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); + return readRegister(REG_MODEM_CONFIG_2) >> 4; } -void LoRaClass::dumpRegisters(Stream& out) +long LoRaClass::getSignalBandwidth() { - for (uint8_t i = 0; i < 128; i++) { - out.print("0x"); - out.print(i, HEX); - out.print(": 0x"); - out.println(readRegister(i), HEX); + uint8_t bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); + + switch (bw) + { + case 0: return 7.8E3; + case 1: return 10.4E3; + case 2: return 15.6E3; + case 3: return 20.8E3; + case 4: return 31.25E3; + case 5: return 41.7E3; + case 6: return 62.5E3; + case 7: return 125E3; + case 8: return 250E3; + case 9: return 500E3; } + return -1; } void LoRaClass::explicitHeaderMode() { _implicitHeaderMode = 0; - writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe); } void LoRaClass::implicitHeaderMode() { _implicitHeaderMode = 1; - writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01); } +void LoRaClass::setLdoFlag() +{ + // Section 4.1.1.5 + float symbolDuration = 1000.0f / ((float)getSignalBandwidth() / (1u << getSpreadingFactor())); + Serial.print("symbolDuration: "); Serial.println(symbolDuration); + + // Section 4.1.1.6 + bool ldoOn = symbolDuration > 16.0f; + + uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); + bitWrite(config3, 3, ldoOn); + writeRegister(REG_MODEM_CONFIG_3, config3); +} + +void LoRaClass::resetFifo() +{ + // reset FIFO address + writeRegister(REG_FIFO_ADDR_PTR, 0); + _available = 0; + _packetIndex = 0; +} + +ISR_PREFIX void LoRaClass::onDio0Rise() +{ + LoRa.handleDio0Rise(); +} + void LoRaClass::handleDio0Rise() { uint8_t irqFlags = readRegister(REG_IRQ_FLAGS); @@ -715,13 +615,14 @@ void LoRaClass::handleDio0Rise() // clear IRQ's writeRegister(REG_IRQ_FLAGS, irqFlags); - if (irqFlags & IRQ_TX_DONE_MASK) { + if (irqFlags & IRQ_TX_DONE_MASK) + { _transmitting = false; - if (_onTxDone) { + if (_onTxDone) _onTxDone(); - } } - else if ((irqFlags & IRQ_RX_DONE_MASK) && !(irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK)) { + else if ((irqFlags & IRQ_RX_DONE_MASK) && !(irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK)) + { // received a packet _packetIndex = 0; @@ -731,20 +632,11 @@ void LoRaClass::handleDio0Rise() // set FIFO address to current RX address writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); - if (_onReceive) { - _onReceive(_available); - } + if (_onRxDone) + _onRxDone(_available); } } -void LoRaClass::resetFifo() -{ - // reset FIFO address - writeRegister(REG_FIFO_ADDR_PTR, 0); - _available = 0; - _packetIndex = 0; -} - uint8_t LoRaClass::readRegister(uint8_t address) { return singleTransfer(address & 0x7f, 0x00); @@ -771,14 +663,4 @@ uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value) return response; } -void LoRaClass::debug() -{ - Serial.print("mode: "); Serial.print(readRegister(REG_OP_MODE), BIN); Serial.print(" status: "); Serial.println(readRegister(0x18), BIN); -} - -ISR_PREFIX void LoRaClass::onDio0Rise() -{ - LoRa.handleDio0Rise(); -} - LoRaClass LoRa; diff --git a/src/LoRa.h b/src/LoRa.h index b0b2fa9..77c045c 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -20,37 +20,18 @@ class LoRaClass : public Stream { public: LoRaClass(); + // HW config + void setPins(uint8_t ss = LORA_DEFAULT_SS_PIN, + uint8_t reset = LORA_DEFAULT_RESET_PIN, + uint8_t dio0 = LORA_DEFAULT_DIO0_PIN); + void setSPI(SPIClass& spi) { _spi = &spi; } + void setSPIFrequency(uint32_t frequency); + + // initiate / terminate connection with radio bool begin(long frequency); void end(); - bool beginPacket(int implicitHeader = false); - bool endPacket(bool async = false); - - uint8_t parsePacket(uint8_t size = 0); - int packetRssi(); - float packetSnr(); - long packetFrequencyError(); - - int rssi(); - - // from Print - virtual size_t write(uint8_t byte); - virtual size_t write(const uint8_t *buffer, size_t size); - - // from Stream - virtual int available(); - virtual int read(); - virtual int peek(); - virtual void flush(); - - void onReceive(void(*callback)(uint8_t)); - void onTxDone(void(*callback)()); - - void continuousRx(uint8_t size = 0); - void singleRx(); - void idle(); - void sleep(); - + // radio config void setTxPower(uint8_t level, uint8_t outputPin = PA_OUTPUT_PA_BOOST_PIN); void setFrequency(long frequency); void setSpreadingFactor(uint8_t sf); @@ -62,44 +43,61 @@ class LoRaClass : public Stream { void disableCrc(); void enableInvertIQ(); void disableInvertIQ(); + void setOCP(uint8_t mA); + void setGain(uint8_t gain); - void setOCP(uint8_t mA); // Over Current Protection control + // radio modes + void continuousRx(uint8_t size = 0); + void singleRx(); + void idle(); + void sleep(); - void setGain(uint8_t gain); // Set LNA gain + // TX + void beginPacket(int implicitHeader = false); + virtual size_t write(uint8_t byte); + virtual size_t write(const uint8_t *buffer, size_t size); + void endPacket(bool async = false); - // deprecated - void crc() { enableCrc(); } - void noCrc() { disableCrc(); } + // RX + virtual int available(); + virtual int read(); + virtual int peek(); + virtual void flush() {} + int packetRssi(); + float packetSnr(); + long packetFrequencyError(); + // other functionality + int rssi(); uint8_t random(); + void onRxDone(void(*callback)(uint8_t)) { _onRxDone = callback; } + void onTxDone(void(*callback)()) { _onTxDone = callback; } - void setPins(uint8_t ss = LORA_DEFAULT_SS_PIN, uint8_t reset = LORA_DEFAULT_RESET_PIN, uint8_t dio0 = LORA_DEFAULT_DIO0_PIN); - void setSPI(SPIClass& spi); - void setSPIFrequency(uint32_t frequency); - + // debug void dumpRegisters(Stream& out); void debug(); private: - void explicitHeaderMode(); - void implicitHeaderMode(); - - void handleDio0Rise(); - // bool isTransmitting(); - void resetFifo(); - + // get radio config uint8_t getSpreadingFactor(); long getSignalBandwidth(); + // set radio config + void explicitHeaderMode(); + void implicitHeaderMode(); void setLdoFlag(); + void resetFifo(); + // ISR + static void onDio0Rise(); + void handleDio0Rise(); + + // SPI uint8_t readRegister(uint8_t address); void writeRegister(uint8_t address, uint8_t value); uint8_t singleTransfer(uint8_t address, uint8_t value); - static void onDio0Rise(); - -private: + // member vars SPISettings _spiSettings; SPIClass* _spi; uint8_t _ss; @@ -110,7 +108,7 @@ class LoRaClass : public Stream { volatile bool _transmitting; volatile uint8_t _packetIndex; volatile uint8_t _available; - void (*_onReceive)(uint8_t); + void (*_onRxDone)(uint8_t); void (*_onTxDone)(); }; From 85d6e1703e2c639cda774da706b659ec1c8263b7 Mon Sep 17 00:00:00 2001 From: Matt Mason Date: Sat, 31 Aug 2024 23:27:58 -0500 Subject: [PATCH 4/9] Add DIO3 support & Add txPower to begin() --- src/LoRa.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++------ src/LoRa.h | 6 ++++- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 10f5c80..c21ee67 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -16,6 +16,7 @@ #define REG_FIFO_TX_BASE_ADDR 0x0e #define REG_FIFO_RX_BASE_ADDR 0x0f #define REG_FIFO_RX_CURRENT_ADDR 0x10 +#define REG_IRQ_FLAGS_MASK 0x11 #define REG_IRQ_FLAGS 0x12 #define REG_RX_NB_BYTES 0x13 #define REG_PKT_SNR_VALUE 0x19 @@ -51,8 +52,14 @@ // PA config #define PA_BOOST 0x80 +// DIO mapping +#define DIO0_RX_DONE 0x00 +#define DIO0_TX_DONE 0x40 +#define DIO3_VALID_HEADER 0x01 + // IRQ masks #define IRQ_TX_DONE_MASK 0x08 +#define IRQ_VALID_HEADER_MASK 0x10 #define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 #define IRQ_RX_DONE_MASK 0x40 @@ -101,7 +108,7 @@ void LoRaClass::setSPIFrequency(uint32_t frequency) _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); } -bool LoRaClass::begin(long frequency) +bool LoRaClass::begin(long frequency, uint8_t txPower) { // setup pins pinMode(_ss, OUTPUT); @@ -140,14 +147,20 @@ bool LoRaClass::begin(long frequency) writeRegister(REG_FIFO_TX_BASE_ADDR, 0); writeRegister(REG_FIFO_RX_BASE_ADDR, 0); + // set IRQ mask + writeRegister(REG_IRQ_FLAGS_MASK, ~(IRQ_TX_DONE_MASK & + IRQ_VALID_HEADER_MASK & + IRQ_PAYLOAD_CRC_ERROR_MASK & + IRQ_RX_DONE_MASK)); + // set LNA boost writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03); // set auto AGC writeRegister(REG_MODEM_CONFIG_3, 0x04); - // set output power to 17 dBm - setTxPower(17); + // set output power + setTxPower(txPower); // put in standby mode idle(); @@ -355,7 +368,7 @@ void LoRaClass::continuousRx(uint8_t size) while (_transmitting) yield(); - writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE + writeRegister(REG_DIO_MAPPING_1, DIO0_RX_DONE & DIO3_VALID_HEADER); if (size > 0) { @@ -379,7 +392,7 @@ void LoRaClass::singleRx() // reset FIFO address resetFifo(); - writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE + writeRegister(REG_DIO_MAPPING_1, DIO0_RX_DONE & DIO3_VALID_HEADER); // put in single RX mode writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); @@ -440,7 +453,7 @@ size_t LoRaClass::write(const uint8_t *buffer, size_t size) void LoRaClass::endPacket(bool blocking) { - writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE + writeRegister(REG_DIO_MAPPING_1, DIO0_TX_DONE & DIO3_VALID_HEADER); // put in TX mode writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); @@ -523,6 +536,27 @@ uint8_t LoRaClass::random() return readRegister(REG_RSSI_WIDEBAND); } +void LoRaClass::onValidHeader(void(*callback)(), uint8_t dio3) +{ + _onValidHeader = callback; + + if (_onValidHeader) // setup DIO3 and attach ISR + { + pinMode(dio3, INPUT); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.usingInterrupt(digitalPinToInterrupt(dio3)); +#endif + attachInterrupt(digitalPinToInterrupt(dio3), LoRaClass::onDio3Rise, RISING); + } + else // detach ISR + { + detachInterrupt(digitalPinToInterrupt(dio3)); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.notUsingInterrupt(digitalPinToInterrupt(dio3)); +#endif + } +} + void LoRaClass::dumpRegisters(Stream& out) { for (uint8_t i = 0; i < 128; i++) @@ -613,7 +647,7 @@ void LoRaClass::handleDio0Rise() // Serial.print("---- IRQ: "); Serial.println(irqFlags, BIN); // clear IRQ's - writeRegister(REG_IRQ_FLAGS, irqFlags); + writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK & IRQ_PAYLOAD_CRC_ERROR_MASK & IRQ_RX_DONE_MASK); if (irqFlags & IRQ_TX_DONE_MASK) { @@ -637,6 +671,26 @@ void LoRaClass::handleDio0Rise() } } +ISR_PREFIX void LoRaClass::onDio3Rise() +{ + LoRa.handleDio3Rise(); +} + +void LoRaClass::handleDio3Rise() +{ + uint8_t irqFlags = readRegister(REG_IRQ_FLAGS); + // Serial.print("---- IRQ: "); Serial.println(irqFlags, BIN); + + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, IRQ_VALID_HEADER_MASK); + + if (irqFlags & IRQ_VALID_HEADER_MASK) + { + if (_onValidHeader) + _onValidHeader(); + } +} + uint8_t LoRaClass::readRegister(uint8_t address) { return singleTransfer(address & 0x7f, 0x00); diff --git a/src/LoRa.h b/src/LoRa.h index 77c045c..2d4684e 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -28,7 +28,7 @@ class LoRaClass : public Stream { void setSPIFrequency(uint32_t frequency); // initiate / terminate connection with radio - bool begin(long frequency); + bool begin(long frequency, uint8_t txPower); void end(); // radio config @@ -70,6 +70,7 @@ class LoRaClass : public Stream { // other functionality int rssi(); uint8_t random(); + void onValidHeader(void(*callback)(), uint8_t dio3 = 0); void onRxDone(void(*callback)(uint8_t)) { _onRxDone = callback; } void onTxDone(void(*callback)()) { _onTxDone = callback; } @@ -91,6 +92,8 @@ class LoRaClass : public Stream { // ISR static void onDio0Rise(); void handleDio0Rise(); + static void onDio3Rise(); + void handleDio3Rise(); // SPI uint8_t readRegister(uint8_t address); @@ -108,6 +111,7 @@ class LoRaClass : public Stream { volatile bool _transmitting; volatile uint8_t _packetIndex; volatile uint8_t _available; + void (*_onValidHeader)(); void (*_onRxDone)(uint8_t); void (*_onTxDone)(); }; From f16cc0490efd4a618fbed765a03d1595b4d18f4c Mon Sep 17 00:00:00 2001 From: Matt Mason Date: Sat, 7 Sep 2024 14:38:27 -0500 Subject: [PATCH 5/9] Cleanup --- src/LoRa.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index c21ee67..00d5a47 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -89,6 +89,7 @@ LoRaClass::LoRaClass() : _transmitting(false), _packetIndex(0), _available(0), + _onValidHeader(NULL), _onRxDone(NULL), _onTxDone(NULL) { @@ -132,10 +133,8 @@ bool LoRaClass::begin(long frequency, uint8_t txPower) _spi->begin(); // check version - uint8_t version = readRegister(REG_VERSION); - if (version != 0x12) { + if (readRegister(REG_VERSION) != 0x12) return 0; - } // put in sleep mode sleep(); From 2aff8a96cbd98a0d75618801855e96d8d321c73b Mon Sep 17 00:00:00 2001 From: Matt Mason Date: Sat, 7 Sep 2024 16:03:28 -0500 Subject: [PATCH 6/9] IRQ bugfix and cleanup --- src/LoRa.cpp | 34 +++++++++++++++++----------------- src/LoRa.h | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 00d5a47..1ffd715 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -58,10 +58,10 @@ #define DIO3_VALID_HEADER 0x01 // IRQ masks -#define IRQ_TX_DONE_MASK 0x08 -#define IRQ_VALID_HEADER_MASK 0x10 -#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 -#define IRQ_RX_DONE_MASK 0x40 +#define MASK_IRQ_TX_DONE 0x08 +#define MASK_IRQ_VALID_HEADER 0x10 +#define MASK_IRQ_PAYLOAD_CRC_ERROR 0x20 +#define MASK_IRQ_RX_DONE 0x40 // RF #define RF_MID_BAND_THRESHOLD 525E6 @@ -146,11 +146,11 @@ bool LoRaClass::begin(long frequency, uint8_t txPower) writeRegister(REG_FIFO_TX_BASE_ADDR, 0); writeRegister(REG_FIFO_RX_BASE_ADDR, 0); - // set IRQ mask - writeRegister(REG_IRQ_FLAGS_MASK, ~(IRQ_TX_DONE_MASK & - IRQ_VALID_HEADER_MASK & - IRQ_PAYLOAD_CRC_ERROR_MASK & - IRQ_RX_DONE_MASK)); + // disable unused IRQs + writeRegister(REG_IRQ_FLAGS_MASK, ~(MASK_IRQ_TX_DONE | + MASK_IRQ_VALID_HEADER | + MASK_IRQ_PAYLOAD_CRC_ERROR | + MASK_IRQ_RX_DONE)); // set LNA boost writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03); @@ -367,7 +367,7 @@ void LoRaClass::continuousRx(uint8_t size) while (_transmitting) yield(); - writeRegister(REG_DIO_MAPPING_1, DIO0_RX_DONE & DIO3_VALID_HEADER); + writeRegister(REG_DIO_MAPPING_1, DIO0_RX_DONE | DIO3_VALID_HEADER); if (size > 0) { @@ -391,7 +391,7 @@ void LoRaClass::singleRx() // reset FIFO address resetFifo(); - writeRegister(REG_DIO_MAPPING_1, DIO0_RX_DONE & DIO3_VALID_HEADER); + writeRegister(REG_DIO_MAPPING_1, DIO0_RX_DONE | DIO3_VALID_HEADER); // put in single RX mode writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); @@ -452,7 +452,7 @@ size_t LoRaClass::write(const uint8_t *buffer, size_t size) void LoRaClass::endPacket(bool blocking) { - writeRegister(REG_DIO_MAPPING_1, DIO0_TX_DONE & DIO3_VALID_HEADER); + writeRegister(REG_DIO_MAPPING_1, DIO0_TX_DONE | DIO3_VALID_HEADER); // put in TX mode writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); @@ -646,15 +646,15 @@ void LoRaClass::handleDio0Rise() // Serial.print("---- IRQ: "); Serial.println(irqFlags, BIN); // clear IRQ's - writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK & IRQ_PAYLOAD_CRC_ERROR_MASK & IRQ_RX_DONE_MASK); + writeRegister(REG_IRQ_FLAGS, MASK_IRQ_TX_DONE & MASK_IRQ_PAYLOAD_CRC_ERROR & MASK_IRQ_RX_DONE); - if (irqFlags & IRQ_TX_DONE_MASK) + if (irqFlags & MASK_IRQ_TX_DONE) { _transmitting = false; if (_onTxDone) _onTxDone(); } - else if ((irqFlags & IRQ_RX_DONE_MASK) && !(irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK)) + else if ((irqFlags & MASK_IRQ_RX_DONE) && !(irqFlags & MASK_IRQ_PAYLOAD_CRC_ERROR)) { // received a packet _packetIndex = 0; @@ -681,9 +681,9 @@ void LoRaClass::handleDio3Rise() // Serial.print("---- IRQ: "); Serial.println(irqFlags, BIN); // clear IRQ's - writeRegister(REG_IRQ_FLAGS, IRQ_VALID_HEADER_MASK); + writeRegister(REG_IRQ_FLAGS, MASK_IRQ_VALID_HEADER); - if (irqFlags & IRQ_VALID_HEADER_MASK) + if (irqFlags & MASK_IRQ_VALID_HEADER) { if (_onValidHeader) _onValidHeader(); diff --git a/src/LoRa.h b/src/LoRa.h index 2d4684e..e3d377e 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -56,7 +56,7 @@ class LoRaClass : public Stream { void beginPacket(int implicitHeader = false); virtual size_t write(uint8_t byte); virtual size_t write(const uint8_t *buffer, size_t size); - void endPacket(bool async = false); + void endPacket(bool blocking = false); // RX virtual int available(); From 8eb7b5711c16960ca497334400644605e81df6a9 Mon Sep 17 00:00:00 2001 From: Matt Mason Date: Sun, 8 Sep 2024 16:08:42 -0500 Subject: [PATCH 7/9] Fix one more IRQ bug --- src/LoRa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 1ffd715..fc6dd59 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -646,7 +646,7 @@ void LoRaClass::handleDio0Rise() // Serial.print("---- IRQ: "); Serial.println(irqFlags, BIN); // clear IRQ's - writeRegister(REG_IRQ_FLAGS, MASK_IRQ_TX_DONE & MASK_IRQ_PAYLOAD_CRC_ERROR & MASK_IRQ_RX_DONE); + writeRegister(REG_IRQ_FLAGS, MASK_IRQ_TX_DONE | MASK_IRQ_PAYLOAD_CRC_ERROR | MASK_IRQ_RX_DONE); if (irqFlags & MASK_IRQ_TX_DONE) { From 81f53e53c9d7a4a77578007528731b41b302e034 Mon Sep 17 00:00:00 2001 From: Matt Mason Date: Sun, 8 Sep 2024 19:40:49 -0500 Subject: [PATCH 8/9] Add validSignalDetected() --- src/LoRa.cpp | 15 ++++++++++++++- src/LoRa.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/LoRa.cpp b/src/LoRa.cpp index fc6dd59..78856ea 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -19,6 +19,7 @@ #define REG_IRQ_FLAGS_MASK 0x11 #define REG_IRQ_FLAGS 0x12 #define REG_RX_NB_BYTES 0x13 +#define REG_MODEM_STAT 0x18 #define REG_PKT_SNR_VALUE 0x19 #define REG_PKT_RSSI_VALUE 0x1a #define REG_RSSI_VALUE 0x1b @@ -63,6 +64,13 @@ #define MASK_IRQ_PAYLOAD_CRC_ERROR 0x20 #define MASK_IRQ_RX_DONE 0x40 +// modem status masks +#define MASK_MODEM_VALID_SIGNAL 0x01 +#define MASK_MODEM_SYNCED 0x02 +#define MASK_MODEM_RX_ACTIVE 0x04 +#define MASK_MODEM_VALID_HEADER 0x08 +#define MASK_MODEM_CLEAR 0x10 + // RF #define RF_MID_BAND_THRESHOLD 525E6 #define RSSI_OFFSET_HF_PORT 157 @@ -525,6 +533,11 @@ long LoRaClass::packetFrequencyError() return static_cast(fError); } +bool LoRaClass::validSignalDetected() +{ + return readRegister(REG_MODEM_STAT) & MASK_MODEM_VALID_SIGNAL; +} + int LoRaClass::rssi() { return readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT); @@ -569,7 +582,7 @@ void LoRaClass::dumpRegisters(Stream& out) void LoRaClass::debug() { - Serial.print("mode: "); Serial.print(readRegister(REG_OP_MODE), BIN); Serial.print(" status: "); Serial.println(readRegister(0x18), BIN); + Serial.print("mode: "); Serial.print(readRegister(REG_OP_MODE), BIN); Serial.print(" status: "); Serial.println(readRegister(REG_MODEM_STAT), BIN); } //****************************************************************************** diff --git a/src/LoRa.h b/src/LoRa.h index e3d377e..304290d 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -66,6 +66,7 @@ class LoRaClass : public Stream { int packetRssi(); float packetSnr(); long packetFrequencyError(); + bool validSignalDetected(); // other functionality int rssi(); From def6aef6325eeb1ce118a46b2c5a783e54425f79 Mon Sep 17 00:00:00 2001 From: Matt Mason Date: Sun, 8 Sep 2024 23:48:58 -0500 Subject: [PATCH 9/9] Add isTransmitting() --- src/LoRa.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/LoRa.h b/src/LoRa.h index 304290d..1c84fea 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -57,6 +57,7 @@ class LoRaClass : public Stream { virtual size_t write(uint8_t byte); virtual size_t write(const uint8_t *buffer, size_t size); void endPacket(bool blocking = false); + bool isTransmitting() { return _transmitting; } // RX virtual int available();