diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index a5655db..ef7e68f 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -38,8 +38,6 @@ jobs: - 'lib/BoardFinder' - 'lib/ConfigurationManagement' #- 'lib/Display' - #- 'lib/LoRa' - - 'lib/LoRa_APRS' #- 'lib/NTPClient' - 'lib/PowerManagement' - 'lib/System' diff --git a/lib/LoRa/LoRa.cpp b/lib/LoRa/LoRa.cpp deleted file mode 100644 index 2422ca8..0000000 --- a/lib/LoRa/LoRa.cpp +++ /dev/null @@ -1,636 +0,0 @@ -// Copyright (c) Sandeep Mistry. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#include - -// registers -#define REG_FIFO 0x00 -#define REG_OP_MODE 0x01 -#define REG_FRF_MSB 0x06 -#define REG_FRF_MID 0x07 -#define REG_FRF_LSB 0x08 -#define REG_PA_CONFIG 0x09 -#define REG_OCP 0x0b -#define REG_LNA 0x0c -#define REG_FIFO_ADDR_PTR 0x0d -#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 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 -#define REG_MODEM_CONFIG_1 0x1d -#define REG_MODEM_CONFIG_2 0x1e -#define REG_PREAMBLE_MSB 0x20 -#define REG_PREAMBLE_LSB 0x21 -#define REG_PAYLOAD_LENGTH 0x22 -#define REG_MODEM_CONFIG_3 0x26 -#define REG_FREQ_ERROR_MSB 0x28 -#define REG_FREQ_ERROR_MID 0x29 -#define REG_FREQ_ERROR_LSB 0x2a -#define REG_RSSI_WIDEBAND 0x2c -#define REG_DETECTION_OPTIMIZE 0x31 -#define REG_INVERTIQ 0x33 -#define REG_DETECTION_THRESHOLD 0x37 -#define REG_SYNC_WORD 0x39 -#define REG_INVERTIQ2 0x3b -#define REG_DIO_MAPPING_1 0x40 -#define REG_VERSION 0x42 -#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 - -// PA config -#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 - -#define MAX_PKT_LENGTH 255 - -#if (ESP8266 || ESP32) -#define ISR_PREFIX ICACHE_RAM_ATTR -#else -#define ISR_PREFIX -#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), _packetIndex(0), _implicitHeaderMode(0) { - // overide Stream timeout value - setTimeout(0); -} - -int 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); - // set SS high - digitalWrite(_ss, HIGH); - - if (_reset != -1) { - pinMode(_reset, OUTPUT); - - // perform reset - digitalWrite(_reset, LOW); - delay(10); - digitalWrite(_reset, HIGH); - delay(10); - } - - // start SPI - _spi->begin(); - - // check version - uint8_t version = readRegister(REG_VERSION); - if (version != 0x12) { - return 0; - } - - // put in sleep mode - sleep(); - - // set frequency - setFrequency(frequency); - - // 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) | 0x01); - - // set auto AGC - writeRegister(REG_MODEM_CONFIG_3, 0x04); - - // set output power to 17 dBm - setTxPower(17); - - // put in standby mode - idle(); - - return 1; -} - -void LoRaClass::end() { - // put in sleep mode - sleep(); - - // stop SPI - _spi->end(); -} - -int LoRaClass::beginPacket(int implicitHeader) { - if (isTransmitting()) { - return 0; - } - - // put in standby mode - idle(); - - if (implicitHeader) { - implicitHeaderMode(); - } else { - explicitHeaderMode(); - } - - // reset FIFO address and paload length - writeRegister(REG_FIFO_ADDR_PTR, 0); - writeRegister(REG_PAYLOAD_LENGTH, 0); - - return 1; -} - -int LoRaClass::endPacket(bool async) { - - // put in TX mode - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); - - if (!async) { - // wait for TX done - while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { - yield(); - } - // clear IRQ's - writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); - } - - return 1; -} - -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); - } - - return false; -} - -int LoRaClass::parsePacket(int size) { - int packetLength = 0; - int irqFlags = readRegister(REG_IRQ_FLAGS); - - if (size > 0) { - implicitHeaderMode(); - - writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); - } else { - explicitHeaderMode(); - } - - // 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) { - packetLength = readRegister(REG_PAYLOAD_LENGTH); - } else { - packetLength = 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 - writeRegister(REG_FIFO_ADDR_PTR, 0); - - // put in single RX mode - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); - } - - return packetLength; -} - -int LoRaClass::packetRssi() { - 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; -} - -bool LoRaClass::rxSignalDetected() { - return (readRegister(REG_MODEM_STAT) & 0x01) == 0x01; -} - -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)); - - 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 - - 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)); -} - -size_t LoRaClass::write(uint8_t byte) { - return write(&byte, sizeof(byte)); -} - -size_t LoRaClass::write(const uint8_t *buffer, size_t size) { - int currentLength = readRegister(REG_PAYLOAD_LENGTH); - - // check size - if ((currentLength + size) > MAX_PKT_LENGTH) { - size = MAX_PKT_LENGTH - currentLength; - } - - // write data - for (size_t i = 0; i < size; i++) { - writeRegister(REG_FIFO, buffer[i]); - } - - // update length - writeRegister(REG_PAYLOAD_LENGTH, currentLength + size); - - return size; -} - -int LoRaClass::available() { - return (readRegister(REG_RX_NB_BYTES) - _packetIndex); -} - -int LoRaClass::read() { - if (!available()) { - return -1; - } - - _packetIndex++; - - return readRegister(REG_FIFO); -} - -int LoRaClass::peek() { - if (!available()) { - return -1; - } - - // store current FIFO address - int currentAddress = readRegister(REG_FIFO_ADDR_PTR); - - // read - uint8_t b = readRegister(REG_FIFO); - - // restore FIFO address - writeRegister(REG_FIFO_ADDR_PTR, currentAddress); - - return b; -} - -void LoRaClass::flush() { -} - -void LoRaClass::receive(int size) { - - writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE - - if (size > 0) { - implicitHeaderMode(); - - writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); - } else { - explicitHeaderMode(); - } - - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); -} - -void LoRaClass::idle() { - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY); -} - -void LoRaClass::sleep() { - writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); -} - -void LoRaClass::setTxPower(int level, int 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; - - // 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)); - } -} - -void LoRaClass::setFrequency(long frequency) { - _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)); -} - -int LoRaClass::getSpreadingFactor() { - return readRegister(REG_MODEM_CONFIG_2) >> 4; -} - -void LoRaClass::setSpreadingFactor(int sf) { - 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); - } - - writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); - setLdoFlag(); -} - -long LoRaClass::getSignalBandwidth() { - byte 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::setSignalBandwidth(long sbw) { - int 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 - long symbolDuration = 1000 / (getSignalBandwidth() / (1L << getSpreadingFactor())); - - // Section 4.1.1.6 - boolean ldoOn = symbolDuration > 16; - - uint8_t config3 = readRegister(REG_MODEM_CONFIG_3); - bitWrite(config3, 3, ldoOn); - writeRegister(REG_MODEM_CONFIG_3, config3); -} - -void LoRaClass::setCodingRate4(int denominator) { - if (denominator < 5) { - denominator = 5; - } else if (denominator > 8) { - denominator = 8; - } - - int cr = denominator - 4; - - writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); -} - -void LoRaClass::setPreambleLength(long length) { - writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); - writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); -} - -void LoRaClass::setSyncWord(int sw) { - writeRegister(REG_SYNC_WORD, sw); -} - -void LoRaClass::enableCrc() { - 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); -} - -void LoRaClass::enableInvertIQ() { - writeRegister(REG_INVERTIQ, 0x66); - writeRegister(REG_INVERTIQ2, 0x19); -} - -void LoRaClass::disableInvertIQ() { - writeRegister(REG_INVERTIQ, 0x27); - writeRegister(REG_INVERTIQ2, 0x1d); -} - -void LoRaClass::setOCP(uint8_t mA) { - uint8_t ocpTrim = 27; - - if (mA <= 120) { - ocpTrim = (mA - 45) / 5; - } else if (mA <= 240) { - ocpTrim = (mA + 30) / 10; - } - - 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); - } else { - // disable AGC - writeRegister(REG_MODEM_CONFIG_3, 0x00); - - // clear Gain and set LNA boost - writeRegister(REG_LNA, 0x01); - - // set gain - writeRegister(REG_LNA, readRegister(REG_LNA) | (gain << 5)); - } -} - -byte LoRaClass::random() { - return readRegister(REG_RSSI_WIDEBAND); -} - -void LoRaClass::setPins(int ss, int reset, int dio0) { - _ss = ss; - _reset = reset; - _dio0 = dio0; -} - -void LoRaClass::setSPI(SPIClass &spi) { - _spi = &spi; -} - -void LoRaClass::setSPIFrequency(uint32_t frequency) { - _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); -} - -void LoRaClass::dumpRegisters(Stream &out) { - for (int 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; - - 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); -} - -uint8_t LoRaClass::readRegister(uint8_t address) { - return singleTransfer(address & 0x7f, 0x00); -} - -void LoRaClass::writeRegister(uint8_t address, uint8_t value) { - singleTransfer(address | 0x80, value); -} - -uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value) { - uint8_t response; - - digitalWrite(_ss, LOW); - - _spi->beginTransaction(_spiSettings); - _spi->transfer(address); - response = _spi->transfer(value); - _spi->endTransaction(); - - digitalWrite(_ss, HIGH); - - return response; -} diff --git a/lib/LoRa/LoRa.h b/lib/LoRa/LoRa.h deleted file mode 100644 index 45c92bd..0000000 --- a/lib/LoRa/LoRa.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) Sandeep Mistry. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#ifndef LORA_H -#define LORA_H - -#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 - -class LoRaClass : public Stream { -public: - LoRaClass(); - - int begin(long frequency); - void end(); - - int beginPacket(int implicitHeader = false); - int endPacket(bool async = false); - - int parsePacket(int size = 0); - int packetRssi(); - float packetSnr(); - long packetFrequencyError(); - bool rxSignalDetected(); - - 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 receive(int size = 0); - - void idle(); - void sleep(); - - void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); - void setFrequency(long frequency); - void setSpreadingFactor(int sf); - void setSignalBandwidth(long sbw); - void setCodingRate4(int denominator); - void setPreambleLength(long length); - void setSyncWord(int 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(); } - - byte random(); - - void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN); - void setSPI(SPIClass& spi); - void setSPIFrequency(uint32_t frequency); - - void dumpRegisters(Stream& out); - -private: - void explicitHeaderMode(); - void implicitHeaderMode(); - - bool isTransmitting(); - - int getSpreadingFactor(); - long getSignalBandwidth(); - - 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); - -private: - SPISettings _spiSettings; - SPIClass* _spi; - int _ss; - int _reset; - int _dio0; - long _frequency; - int _packetIndex; - int _implicitHeaderMode; -}; - -#endif diff --git a/lib/LoRa_APRS/LoRa_APRS.cpp b/lib/LoRa_APRS/LoRa_APRS.cpp deleted file mode 100644 index 48d2dfa..0000000 --- a/lib/LoRa_APRS/LoRa_APRS.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "LoRa_APRS.h" - -LoRa_APRS::LoRa_APRS() : _RxFrequency(433775000), _TxFrequency(433775000) { -} - -bool LoRa_APRS::checkMessage() { - if (!parsePacket()) { - return false; - } - // read header: - char dummy[4]; - readBytes(dummy, 3); - if (dummy[0] != '<') { - // is no APRS message, ignore message - while (available()) { - read(); - } - return false; - } - // read APRS data: - String str; - while (available()) { - str += (char)read(); - } - _LastReceivedMsg = std::shared_ptr(new APRSMessage()); - _LastReceivedMsg->decode(str); - return true; -} - -std::shared_ptr LoRa_APRS::getMessage() { - return _LastReceivedMsg; -} - -void LoRa_APRS::sendMessage(const std::shared_ptr msg) { - setFrequency(_TxFrequency); - String data = msg->encode(); - beginPacket(); - // Header: - write('<'); - write(0xFF); - write(0x01); - // APRS Data: - write((const uint8_t *)data.c_str(), data.length()); - endPacket(); - setFrequency(_RxFrequency); -} - -void LoRa_APRS::setRxFrequency(long frequency) { - _RxFrequency = frequency; - setFrequency(_RxFrequency); -} - -void LoRa_APRS::setRxGain(uint8_t gain) { - setGain(gain); -} - -// cppcheck-suppress unusedFunction -long LoRa_APRS::getRxFrequency() const { - return _RxFrequency; -} - -void LoRa_APRS::setTxFrequency(long frequency) { - _TxFrequency = frequency; -} - -// cppcheck-suppress unusedFunction -long LoRa_APRS::getTxFrequency() const { - return _TxFrequency; -} diff --git a/lib/LoRa_APRS/LoRa_APRS.h b/lib/LoRa_APRS/LoRa_APRS.h deleted file mode 100644 index 3d6eff4..0000000 --- a/lib/LoRa_APRS/LoRa_APRS.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef LORA_H_ -#define LORA_H_ - -#include - -#include -#include -#include - -class LoRa_APRS : public LoRaClass { -public: - LoRa_APRS(); - - bool checkMessage(); - std::shared_ptr getMessage(); - - void sendMessage(const std::shared_ptr msg); - - void setRxFrequency(long frequency); - long getRxFrequency() const; - - void setRxGain(uint8_t gain); - - void setTxFrequency(long frequency); - long getTxFrequency() const; - -private: - std::shared_ptr _LastReceivedMsg; - long _RxFrequency; - long _TxFrequency; -}; - -#endif diff --git a/platformio.ini b/platformio.ini index a2f5cb3..7c1aa1c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,6 +16,7 @@ lib_deps = knolleary/PubSubClient@^2.8 mikalhart/TinyGPSPlus @ 1.0.2 shaggydog/OneButton @ 1.5.0 + jgromes/RadioLib @ 5.1.2 check_tool = cppcheck check_flags = cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK --force lib -ilib/TimeLib -ilib/LoRa -ilib/NTPClient diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 9ec796b..11adfdf 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -13,14 +13,14 @@ #include "TaskEth.h" #include "TaskFTP.h" #include "TaskMQTT.h" -#include "TaskModem.h" #include "TaskNTP.h" #include "TaskOTA.h" +#include "TaskRadiolib.h" #include "TaskRouter.h" #include "TaskWifi.h" #include "project_configuration.h" -#define VERSION "22.14.0" +#define VERSION "22.20.0" #define MODULE_NAME "Main" String create_lat_aprs(double lat); @@ -35,16 +35,17 @@ System LoRaSystem; Configuration userConfig; DisplayTask displayTask; -ModemTask modemTask(fromModem, toModem); -EthTask ethTask; -WifiTask wifiTask; -OTATask otaTask; -NTPTask ntpTask; -FTPTask ftpTask; -MQTTTask mqttTask(toMQTT); -AprsIsTask aprsIsTask(toAprsIs); -RouterTask routerTask(fromModem, toModem, toAprsIs, toMQTT); -BeaconTask beaconTask(toModem, toAprsIs); +// ModemTask modemTask(fromModem, toModem); +RadiolibTask modemTask(fromModem, toModem); +EthTask ethTask; +WifiTask wifiTask; +OTATask otaTask; +NTPTask ntpTask; +FTPTask ftpTask; +MQTTTask mqttTask(toMQTT); +AprsIsTask aprsIsTask(toAprsIs); +RouterTask routerTask(fromModem, toModem, toAprsIs, toMQTT); +BeaconTask beaconTask(toModem, toAprsIs); void setup() { Serial.begin(115200); diff --git a/src/Task.h b/src/Task.h index cd4b3da..a3b3fb9 100644 --- a/src/Task.h +++ b/src/Task.h @@ -7,6 +7,7 @@ enum TaskNames TaskEth, TaskFtp, TaskModem, + TaskRadiolib, TaskNtp, TaskOta, TaskWifi, @@ -16,15 +17,16 @@ enum TaskNames TaskSize }; -#define TASK_APRS_IS "AprsIsTask" -#define TASK_ETH "EthTask" -#define TASK_FTP "FTPTask" -#define TASK_MODEM "ModemTask" -#define TASK_NTP "NTPTask" -#define TASK_OTA "OTATask" -#define TASK_WIFI "WifiTask" -#define TASK_ROUTER "RouterTask" -#define TASK_MQTT "MQTTTask" -#define TASK_BEACON "BeaconTask" +#define TASK_APRS_IS "AprsIsTask" +#define TASK_ETH "EthTask" +#define TASK_FTP "FTPTask" +#define TASK_MODEM "ModemTask" +#define TASK_RADIOLIB "RadiolibTask" +#define TASK_NTP "NTPTask" +#define TASK_OTA "OTATask" +#define TASK_WIFI "WifiTask" +#define TASK_ROUTER "RouterTask" +#define TASK_MQTT "MQTTTask" +#define TASK_BEACON "BeaconTask" #endif diff --git a/src/TaskModem.cpp b/src/TaskModem.cpp deleted file mode 100644 index 05e4fcd..0000000 --- a/src/TaskModem.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include - -#include - -#include "Task.h" -#include "TaskAprsIs.h" -#include "TaskModem.h" -#include "project_configuration.h" - -ModemTask::ModemTask(TaskQueue> &fromModem, TaskQueue> &toModem) : Task(TASK_MODEM, TaskModem), _lora_aprs(), _fromModem(fromModem), _toModem(toModem) { -} - -ModemTask::~ModemTask() { -} - -bool ModemTask::setup(System &system) { - SPI.begin(system.getBoardConfig()->LoraSck, system.getBoardConfig()->LoraMiso, system.getBoardConfig()->LoraMosi, system.getBoardConfig()->LoraCS); - _lora_aprs.setPins(system.getBoardConfig()->LoraCS, system.getBoardConfig()->LoraReset, system.getBoardConfig()->LoraIRQ); - if (!_lora_aprs.begin(system.getUserConfig()->lora.frequencyRx)) { - system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "Starting LoRa failed!"); - _stateInfo = "LoRa-Modem failed"; - _state = Error; - while (true) - ; - } - _lora_aprs.setRxFrequency(system.getUserConfig()->lora.frequencyRx); - _lora_aprs.setRxGain(system.getUserConfig()->lora.gainRx); - _lora_aprs.setTxFrequency(system.getUserConfig()->lora.frequencyTx); - _lora_aprs.setTxPower(system.getUserConfig()->lora.power); - _lora_aprs.setSpreadingFactor(system.getUserConfig()->lora.spreadingFactor); - _lora_aprs.setSignalBandwidth(system.getUserConfig()->lora.signalBandwidth); - _lora_aprs.setCodingRate4(system.getUserConfig()->lora.codingRate4); - _lora_aprs.enableCrc(); - - _stateInfo = ""; - return true; -} - -bool ModemTask::loop(System &system) { - if (_lora_aprs.checkMessage()) { - std::shared_ptr msg = _lora_aprs.getMessage(); - system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] Received packet '%s' with RSSI %ddBm, SNR %.2fdB and FreqErr %dHz", timeString().c_str(), msg->toString().c_str(), _lora_aprs.packetRssi(), _lora_aprs.packetSnr(), -_lora_aprs.packetFrequencyError()); - _fromModem.addElement(msg); - system.getDisplay().addFrame(std::shared_ptr(new TextFrame("LoRa", msg->toString().c_str()))); - } - - if (!_toModem.empty()) { - if (_lora_aprs.rxSignalDetected()) { - system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] RX signal detected. Waiting TX", timeString().c_str()); - delay(1000); - } else { - std::shared_ptr msg = _toModem.getElement(); - if (system.getUserConfig()->lora.tx_enable) { - system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] Transmitting packet '%s'", timeString().c_str(), msg->toString().c_str()); - _lora_aprs.sendMessage(msg); - system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] TX done", timeString().c_str()); - } else { - system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] NOT transmitting packet as TX is not enabled '%s'", timeString().c_str(), msg->toString().c_str()); - } - } - } - - return true; -} diff --git a/src/TaskModem.h b/src/TaskModem.h deleted file mode 100644 index 6087b67..0000000 --- a/src/TaskModem.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef TASK_LORA_H_ -#define TASK_LORA_H_ - -#include -#include -#include - -class ModemTask : public Task { -public: - explicit ModemTask(TaskQueue> &fromModem, TaskQueue> &_toModem); - virtual ~ModemTask(); - - virtual bool setup(System &system) override; - virtual bool loop(System &system) override; - -private: - LoRa_APRS _lora_aprs; - - TaskQueue> &_fromModem; - TaskQueue> &_toModem; -}; - -#endif diff --git a/src/TaskRadiolib.cpp b/src/TaskRadiolib.cpp new file mode 100644 index 0000000..afc7ac2 --- /dev/null +++ b/src/TaskRadiolib.cpp @@ -0,0 +1,212 @@ +#include +#include +#include + +#include "TaskRadiolib.h" + +RadiolibTask::RadiolibTask(TaskQueue> &fromModem, TaskQueue> &toModem) : Task(TASK_RADIOLIB, TaskRadiolib), _fromModem(fromModem), _toModem(toModem) { +} + +RadiolibTask::~RadiolibTask() { + radio->clearDio0Action(); +} + +volatile bool RadiolibTask::enableInterrupt = true; // Need to catch interrupt or not. +volatile bool RadiolibTask::operationDone = false; // Caught IRQ or not. + +void RadiolibTask::setFlag(void) { + if (!enableInterrupt) { + return; + } + + operationDone = true; +} + +bool RadiolibTask::setup(System &system) { + SPI.begin(system.getBoardConfig()->LoraSck, system.getBoardConfig()->LoraMiso, system.getBoardConfig()->LoraMosi, system.getBoardConfig()->LoraCS); + module = new Module(system.getBoardConfig()->LoraCS, system.getBoardConfig()->LoraIRQ, system.getBoardConfig()->LoraReset); + radio = new SX1278(module); + + config = system.getUserConfig()->lora; + + rxEnable = true; + txEnable = config.tx_enable; + + float freqMHz = (float)config.frequencyRx / 1000000; + float BWkHz = (float)config.signalBandwidth / 1000; + + const uint16_t preambleLength = 8; + + int16_t state = radio->begin(freqMHz, BWkHz, config.spreadingFactor, config.codingRate4, RADIOLIB_SX127X_SYNC_WORD, config.power, preambleLength, config.gainRx); + if (state != RADIOLIB_ERR_NONE) { + switch (state) { + case RADIOLIB_ERR_INVALID_FREQUENCY: + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied frequency value (%fMHz) is invalid for this module.", timeString().c_str(), freqMHz); + rxEnable = false; + txEnable = false; + break; + case RADIOLIB_ERR_INVALID_BANDWIDTH: + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied bandwidth value (%fkHz) is invalid for this module. Should be 7800, 10400, 15600, 20800, 31250, 41700 ,62500, 125000, 250000, 500000.", timeString().c_str(), BWkHz); + rxEnable = false; + txEnable = false; + break; + case RADIOLIB_ERR_INVALID_SPREADING_FACTOR: + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied spreading factor value (%d) is invalid for this module.", timeString().c_str(), config.spreadingFactor); + rxEnable = false; + txEnable = false; + break; + case RADIOLIB_ERR_INVALID_CODING_RATE: + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied coding rate value (%d) is invalid for this module.", timeString().c_str(), config.codingRate4); + rxEnable = false; + txEnable = false; + break; + case RADIOLIB_ERR_INVALID_OUTPUT_POWER: + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied output power value (%d) is invalid for this module.", timeString().c_str(), config.power); + txEnable = false; + break; + case RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH: + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied preamble length is invalid.", timeString().c_str()); + txEnable = false; + break; + case RADIOLIB_ERR_INVALID_GAIN: + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied gain value (%d) is invalid.", timeString().c_str(), config.gainRx); + rxEnable = false; + break; + default: + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, code %d", timeString().c_str(), state); + rxEnable = false; + txEnable = false; + } + _stateInfo = "LoRa-Modem failed"; + _state = Error; + } + + state = radio->setCRC(true); + if (state != RADIOLIB_ERR_NONE) { + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] setCRC failed, code %d", timeString().c_str(), state); + _stateInfo = "LoRa-Modem failed"; + _state = Error; + } + + radio->setDio0Action(setFlag); + + if (rxEnable) { + int state = startRX(RADIOLIB_SX127X_RXCONTINUOUS); + if (state != RADIOLIB_ERR_NONE) { + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] startRX failed, code %d", timeString().c_str(), state); + rxEnable = false; + _stateInfo = "LoRa-Modem failed"; + _state = Error; + } + } + + preambleDurationMilliSec = ((uint64_t)(preambleLength + 4) << (config.spreadingFactor + 10 /* to milli-sec */)) / config.signalBandwidth; + + _stateInfo = ""; + return true; +} + +int transmissionState = RADIOLIB_ERR_NONE; +bool transmitFlag = false; // Transmitting or not. + +bool RadiolibTask::loop(System &system) { + if (operationDone) { // occurs interrupt. + enableInterrupt = false; + + if (transmitFlag) { // transmitted. + if (transmissionState == RADIOLIB_ERR_NONE) { + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] TX done", timeString().c_str()); + + } else { + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] transmitFlag failed, code %d", timeString().c_str(), transmissionState); + } + operationDone = false; + transmitFlag = false; + + txWaitTimer.setTimeout(preambleDurationMilliSec * 2); + txWaitTimer.start(); + + } else { // received. + String str; + int state = radio->readData(str); + + if (state != RADIOLIB_ERR_NONE) { + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] readData failed, code %d", timeString().c_str(), state); + } else { + if (str.substring(0, 3) != "<\xff\x01") { + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] Unknown packet '%s' with RSSI %.0fdBm, SNR %.2fdB and FreqErr %dHz", timeString().c_str(), radio->getRSSI(), radio->getSNR(), -radio->getFrequencyError()); + } else { + std::shared_ptr msg = std::shared_ptr(new APRSMessage()); + msg->decode(str.substring(3)); + _fromModem.addElement(msg); + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] Received packet '%s' with RSSI %.0fdBm, SNR %.2fdB and FreqErr %fHz", timeString().c_str(), msg->toString().c_str(), radio->getRSSI(), radio->getSNR(), -radio->getFrequencyError()); + system.getDisplay().addFrame(std::shared_ptr(new TextFrame("LoRa", msg->toString().c_str()))); + } + } + operationDone = false; + } + + if (rxEnable) { + int state = startRX(RADIOLIB_SX127X_RXCONTINUOUS); + if (state != RADIOLIB_ERR_NONE) { + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] startRX failed, code %d", timeString().c_str(), state); + rxEnable = false; + } + } + + enableInterrupt = true; + } else { // not interrupt. + if (!txWaitTimer.check()) { + } else { + if (!txEnable) { + // system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] TX is not enabled", timeString().c_str()); + } else { + if (transmitFlag) { + // system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] TX signal detected. Waiting TX", timeString().c_str()); + } else { + if (!_toModem.empty()) { + if (config.frequencyRx == config.frequencyTx && (radio->getModemStatus() & 0x01) == 0x01) { + // system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] RX signal detected. Waiting TX", timeString().c_str()); + } else { + std::shared_ptr msg = _toModem.getElement(); + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] Transmitting packet '%s'", timeString().c_str(), msg->toString().c_str()); + + int16_t state = startTX("<\xff\x01" + msg->encode()); + if (state != RADIOLIB_ERR_NONE) { + system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] startTX failed, code %d", timeString().c_str(), state); + txEnable = false; + return true; + } + } + } + } + } + } + } + + return true; +} + +int16_t RadiolibTask::startRX(uint8_t mode) { + if (config.frequencyTx != config.frequencyRx) { + int16_t state = radio->setFrequency((float)config.frequencyRx / 1000000); + if (state != RADIOLIB_ERR_NONE) { + return state; + } + } + + return radio->startReceive(0, mode); +} + +int16_t RadiolibTask::startTX(String &str) { + if (config.frequencyTx != config.frequencyRx) { + int16_t state = radio->setFrequency((float)config.frequencyTx / 1000000); + if (state != RADIOLIB_ERR_NONE) { + return state; + } + } + + transmissionState = radio->startTransmit(str); + transmitFlag = true; + return RADIOLIB_ERR_NONE; +} diff --git a/src/TaskRadiolib.h b/src/TaskRadiolib.h new file mode 100644 index 0000000..11e59da --- /dev/null +++ b/src/TaskRadiolib.h @@ -0,0 +1,41 @@ +#ifndef TASK_LORA_H_ +#define TASK_LORA_H_ + +#include "project_configuration.h" +#include +#include +#include +#include + +class RadiolibTask : public Task { +public: + explicit RadiolibTask(TaskQueue> &fromModem, TaskQueue> &_toModem); + virtual ~RadiolibTask(); + + virtual bool setup(System &system) override; + virtual bool loop(System &system) override; + +private: + Module *module; + SX1278 *radio; + + Configuration::LoRa config; + + bool rxEnable, txEnable; + + TaskQueue> &_fromModem; + TaskQueue> &_toModem; + + static volatile bool enableInterrupt; // Need to catch interrupt or not. + static volatile bool operationDone; // Caught IRQ or not. + + static void setFlag(void); + + int16_t startRX(uint8_t mode); + int16_t startTX(String &str); + + uint32_t preambleDurationMilliSec; + Timer txWaitTimer; +}; + +#endif