diff --git a/Config.h b/Config.h index ad06363..262fc6a 100644 --- a/Config.h +++ b/Config.h @@ -1,18 +1,13 @@ #include "ROM.h" +#include "Platform.h" + #ifndef CONFIG_H #define CONFIG_H #define MAJ_VERS 0x01 #define MIN_VERS 0x1B - #define PLATFORM_AVR 0x90 - #define PLATFORM_ESP32 0x80 - - #define MCU_1284P 0x91 - #define MCU_2560 0x92 - #define MCU_ESP32 0x81 - #define BOARD_RNODE 0x31 #define BOARD_HMBRW 0x32 #define BOARD_TBEAM 0x33 @@ -20,23 +15,13 @@ #define BOARD_GENERIC_ESP32 0x35 #define BOARD_LORA32_V2_0 0x36 #define BOARD_LORA32_V2_1 0x37 - + + #define SERIAL_INTERRUPT 0x1 + #define SERIAL_POLLING 0x2 + #define MODE_HOST 0x11 #define MODE_TNC 0x12 - #if defined(__AVR_ATmega1284P__) - #define PLATFORM PLATFORM_AVR - #define MCU_VARIANT MCU_1284P - #elif defined(__AVR_ATmega2560__) - #define PLATFORM PLATFORM_AVR - #define MCU_VARIANT MCU_2560 - #elif defined(ESP32) - #define PLATFORM PLATFORM_ESP32 - #define MCU_VARIANT MCU_ESP32 - #else - #error "The firmware cannot be compiled for the selected MCU variant" - #endif - #define MTU 500 #define SINGLE_MTU 255 #define HEADER_L 1 @@ -54,6 +39,7 @@ const int pin_led_tx = 13; #define BOARD_MODEL BOARD_RNODE + #define SERIAL_EVENTS SERIAL_INTERRUPT #define CONFIG_UART_BUFFER_SIZE 6144 #define CONFIG_QUEUE_SIZE 6144 @@ -70,6 +56,7 @@ const int pin_led_tx = 13; #define BOARD_MODEL BOARD_HMBRW + #define SERIAL_EVENTS SERIAL_INTERRUPT #define CONFIG_UART_BUFFER_SIZE 768 #define CONFIG_QUEUE_SIZE 5120 @@ -130,7 +117,9 @@ #else #error An unsupported board was selected. Cannot compile RNode firmware. #endif - + + #define SERIAL_EVENTS SERIAL_POLLING + #define CONFIG_UART_BUFFER_SIZE 6144 #define CONFIG_QUEUE_SIZE 6144 #define CONFIG_QUEUE_MAX_LENGTH 200 @@ -141,6 +130,22 @@ #define GPS_BAUD_RATE 9600 #define PIN_GPS_TX 12 #define PIN_GPS_RX 34 + #elif MCU_VARIANT == MCU_LINUX + const int pin_cs = -1; + const int pin_reset = -1; + const int pin_dio = -1; + const int pin_led_rx = -1; + const int pin_led_tx = -1; + + #define BOARD_MODEL BOARD_HMBRW + #define SERIAL_EVENTS SERIAL_POLLING + + #define CONFIG_UART_BUFFER_SIZE 6144 + #define CONFIG_QUEUE_SIZE 6144 + #define CONFIG_QUEUE_MAX_LENGTH 200 + + #define EEPROM_SIZE 4096 + #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED #endif #if BOARD_MODEL == BOARD_TBEAM @@ -148,7 +153,12 @@ #define I2C_SCL 22 #define PMU_IRQ 35 #endif - + + #if LIBRARY_TYPE == LIBRARY_C + // We need standard int types before we go any further + #include + #endif + #define eeprom_addr(a) (a+EEPROM_OFFSET) // MCU independent configuration parameters diff --git a/LoRa.cpp b/LoRa.cpp index 304e2df..8d3022b 100644 --- a/LoRa.cpp +++ b/LoRa.cpp @@ -6,23 +6,23 @@ #include "LoRa.h" -#define MCU_1284P 0x91 -#define MCU_2560 0x92 -#define MCU_ESP32 0x81 -#if defined(__AVR_ATmega1284P__) - #define PLATFORM PLATFORM_AVR - #define MCU_VARIANT MCU_1284P -#elif defined(__AVR_ATmega2560__) - #define PLATFORM PLATFORM_AVR - #define MCU_VARIANT MCU_2560 -#elif defined(ESP32) - #define PLATFORM PLATFORM_ESP32 - #define MCU_VARIANT MCU_ESP32 +#if LIBRARY_TYPE == LIBRARY_C + // We need sleep() to use instead of yield() + #include + // And we need to use the filesystem and IOCTLs instead of an SPI global + #include + #include + #include + // And to have memset + #include + // And we need to be able to report errors + #include + #include + // And we need IO formatting functions for the C++-stream dumpRegisters() + #include #endif -#ifndef MCU_VARIANT - #error No MCU variant defined, cannot compile -#endif + #if MCU_VARIANT == MCU_ESP32 #include "soc/rtc_wdt.h" @@ -38,11 +38,14 @@ #define REG_FRF_MID 0x07 #define REG_FRF_LSB 0x08 #define REG_PA_CONFIG 0x09 +#define REG_PA_RAMP 0x0a +#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_MASK 0x11 #define REG_IRQ_FLAGS 0x12 #define REG_RX_NB_BYTES 0x13 #define REG_MODEM_STAT 0x18 @@ -50,19 +53,38 @@ #define REG_PKT_RSSI_VALUE 0x1a #define REG_MODEM_CONFIG_1 0x1d #define REG_MODEM_CONFIG_2 0x1e +#define REG_SYMB_TIMEOUT_LSB 0x1f #define REG_PREAMBLE_MSB 0x20 #define REG_PREAMBLE_LSB 0x21 #define REG_PAYLOAD_LENGTH 0x22 +#define REG_PAYLOAD_MAX_LENGTH 0x23 +#define REG_HOP_PERIOD 0x24 #define REG_MODEM_CONFIG_3 0x26 +#define REG_PPM_CORRECTION 0x27 #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_IF_FREQ_2 0x2f +#define REG_IF_FREQ_1 0x30 #define REG_DETECTION_OPTIMIZE 0x31 +#define REG_INVERT_IQ 0x33 +#define REG_HIGH_BW_OPTIMIZE_1 0x36 #define REG_DETECTION_THRESHOLD 0x37 #define REG_SYNC_WORD 0x39 +#define REG_HIGH_BW_OPTIMIZE_2 0x3a +#define REG_INVERT_IQ_2 0x3b #define REG_DIO_MAPPING_1 0x40 #define REG_VERSION 0x42 +#define REG_TXCO 0x4B +#define REG_PA_DAC 0x4D +// These registers have different values in high and low frequency modes (flag 0x08 in mode) +// We always stay in high frequency mode (flag is 0) +#define REG_AGC_REF 0x61 +#define REG_AGC_THRESHOLD_1 0x62 +#define REG_AGC_THRESHOLD_2 0x63 +#define REG_AGC_THRESHOLD_3 0x64 +#define REG_PLL 0x70 // Modes #define MODE_LONG_RANGE_MODE 0x80 @@ -88,41 +110,50 @@ LoRaClass::LoRaClass() : _frequency(0), _packetIndex(0), _implicitHeaderMode(0), - _onReceive(NULL) + _onReceive(NULL), + _spiBegun(false) { +#if LIBRARY_TYPE == LIBRARY_ARDUINO // overide Stream timeout value setTimeout(0); +#elif LIBRARY_TYPE == LIBRARY_C + _fd = 0; +#endif } int LoRaClass::begin(long frequency) { - // 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); - } +#if LIBRARY_TYPE == LIBRARY_ARDUINO + // setup pins + pinMode(_ss, OUTPUT); + // set SS high + digitalWrite(_ss, HIGH); +#endif +#if LIBRARY_TYPE == LIBRARY_ARDUINO // start SPI SPI.begin(); - - // check version - uint8_t version = readRegister(REG_VERSION); - if (version != 0x12) { +#elif LIBRARY_TYPE == LIBRARY_C + const char* spi_filename = "/dev/spidev0.0"; + // We need to be re-entrant for restart + if (_fd <= 0) { + std::cerr << "Opening SPI device " << spi_filename << std::endl; + _fd = open(spi_filename, O_RDWR); + if (_fd <= 0) { + perror("could not open SPI device"); + exit(1); + } + } else { + std::cerr << "Skipping LoRa SPI reinitialization" << std::endl; + } +#endif + _spiBegun = true; + + if (!resetModem()) { return 0; } - // put in sleep mode - sleep(); - // set frequency setFrequency(frequency); @@ -147,11 +178,21 @@ int LoRaClass::begin(long frequency) void LoRaClass::end() { - // put in sleep mode - sleep(); + // We need to be safe to call when the main loop is shutting down because + // it's in a bad state, even if we ourselves haven't been begun yet. We can't + // safely talk to the modem if the SPI link isn't begun, though. + if (_spiBegun) { + // put in sleep mode + this->sleep(); + } +#if LIBRARY_TYPE == LIBRARY_ARDUINO // stop SPI SPI.end(); +#elif LIBRARY_TYPE == LIBRARY_C + // Don't do anything. We need to keep things open for restart. +#endif + _spiBegun = false; } int LoRaClass::beginPacket(int implicitHeader) @@ -179,7 +220,11 @@ int LoRaClass::endPacket() // wait for TX done while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { +#if LIBRARY_TYPE == LIBRARY_ARDUINO yield(); +#elif LIBRARY_TYPE == LIBRARY_C + ::sleep(0); +#endif } // clear IRQ's @@ -271,13 +316,13 @@ float ISR_VECT LoRaClass::packetSnr() { long LoRaClass::packetFrequencyError() { int32_t freqError = 0; - freqError = static_cast(readRegister(REG_FREQ_ERROR_MSB) & B111); + freqError = static_cast(readRegister(REG_FREQ_ERROR_MSB) & 0b111); 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 + if (readRegister(REG_FREQ_ERROR_MSB) & 0b1000) { // Sign bit is on freqError -= 524288; // B1000'0000'0000'0000'0000 } @@ -350,22 +395,42 @@ void LoRaClass::flush() { } +void LoRaClass::pollReceive() +{ + int irqFlags = readRegister(REG_IRQ_FLAGS); + + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, irqFlags); + + if ((irqFlags & IRQ_RX_DONE_MASK) && !(irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK)) { + // received a packet + handleRx(); + } +} + void LoRaClass::onReceive(void(*callback)(int)) { _onReceive = callback; if (callback) { +#if LIBRARY_TYPE == LIBRARY_ARDUINO pinMode(_dio0, INPUT); +#endif writeRegister(REG_DIO_MAPPING_1, 0x00); + +#if MCU_VARIANT != MCU_LINUX && LIBRARY_TYPE == LIBRARY_ARDUINO #ifdef SPI_HAS_NOTUSINGINTERRUPT SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); #endif attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); +#endif } else { +#if MCU_VARIANT != MCU_LINUX && LIBRARY_TYPE == LIBRARY_ARDUINO detachInterrupt(digitalPinToInterrupt(_dio0)); #ifdef SPI_HAS_NOTUSINGINTERRUPT SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); +#endif #endif } } @@ -572,6 +637,7 @@ void LoRaClass::setSPIFrequency(uint32_t frequency) _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); } +#if LIBRARY_TYPE == LIBRARY_ARDUINO void LoRaClass::dumpRegisters(Stream& out) { for (int i = 0; i < 128; i++) { @@ -581,6 +647,94 @@ void LoRaClass::dumpRegisters(Stream& out) out.println(readRegister(i), HEX); } } +#elif LIBRARY_TYPE == LIBRARY_C +void LoRaClass::dumpRegisters(std::ostream& out) +{ + for (int i = 0; i < 128; i++) { + out << "0x" << std::hex << i << ": 0x" << std::hex << readRegister(i) << std::endl; + } + out << std::dec; +} +#endif + +bool LoRaClass::resetModem() +{ + // Reset the modem to a known good default state and put it into sleep mode. + // Returns false if the modem doesn't appear to be the right version. + #if LIBRARY_TYPE == LIBRARY_ARDUINO + if (_reset != -1) { + pinMode(_reset, OUTPUT); + + // perform reset + digitalWrite(_reset, LOW); + delay(10); + digitalWrite(_reset, HIGH); + delay(10); + } + #endif + // check version + uint8_t version = readRegister(REG_VERSION); + if (version != 0x12) { + return false; + } + + this->sleep(); + + #if LIBRARY_TYPE == LIBRARY_C + byte CLEAN_STATE[] = { + REG_PA_RAMP, 0x09, + REG_FRF_MSB, 0x6c, + REG_FRF_MID, 0x80, + REG_FRF_LSB, 0x00, + REG_PA_CONFIG, 0x4f, + REG_PA_RAMP, 0x09, + REG_OCP, 0x2b, + REG_LNA, 0x20, + REG_FIFO_ADDR_PTR, 0x00, + REG_FIFO_TX_BASE_ADDR, 0x80, + REG_FIFO_RX_BASE_ADDR, 0x00, + REG_FIFO_RX_CURRENT_ADDR, 0x00, + REG_IRQ_FLAGS_MASK, 0x00, + REG_MODEM_CONFIG_1, 0x72, + REG_MODEM_CONFIG_2, 0x70, + REG_SYMB_TIMEOUT_LSB, 0x64, + REG_PREAMBLE_MSB, 0x00, + REG_PREAMBLE_LSB, 0x08, + REG_PAYLOAD_LENGTH, 0x01, + REG_PAYLOAD_MAX_LENGTH, 0xff, + REG_HOP_PERIOD, 0x00, + REG_MODEM_CONFIG_3, 0x04, + REG_PPM_CORRECTION, 0x00, + REG_DETECTION_OPTIMIZE, 0xc3, // Errata says this needs to be set before REG_IF_FREQ_1 and REG_IF_FREQ_2 + REG_IF_FREQ_2, 0x45, // Datasheet says this defaults to 0x20, but dumping says 0x45. + REG_IF_FREQ_1, 0x55, // Datasheet says this defaults to 0x00, but dumping says 0x55. + REG_INVERT_IQ, 0x27, + REG_HIGH_BW_OPTIMIZE_1, 0x03, + REG_DETECTION_THRESHOLD, 0x0a, + REG_SYNC_WORD, 0x12, + REG_HIGH_BW_OPTIMIZE_2, 0x52, // Datasheet says this defaults to 0x20, but dumping says 0x52. + REG_INVERT_IQ_2, 0x1d, + REG_TXCO, 0x09, + REG_PA_DAC, 0x84, + // These are the high frequency mode (mode flag 0x08 is 0) values + REG_AGC_REF, 0x1C, + REG_AGC_THRESHOLD_1, 0x0e, + REG_AGC_THRESHOLD_2, 0x5b, + REG_AGC_THRESHOLD_3, 0xcc, + REG_PLL, 0xd0, + 0, 0 + }; + + + // Manually set important registers to default values because we can't + // reset. + for (int i = 0; CLEAN_STATE[i] != 0; i += 2) { + writeRegister(CLEAN_STATE[i], CLEAN_STATE[i + 1]); + } + #endif + + return true; +} void LoRaClass::explicitHeaderMode() { @@ -606,23 +760,29 @@ void ISR_VECT LoRaClass::handleDio0Rise() if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { // received a packet - _packetIndex = 0; - - // read packet length - int packetLength = _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)); - - if (_onReceive) { - _onReceive(packetLength); - } - - // reset FIFO address - writeRegister(REG_FIFO_ADDR_PTR, 0); + handleRx(); } } +void ISR_VECT LoRaClass::handleRx() +{ + // received a packet + _packetIndex = 0; + + // read packet length + int packetLength = _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)); + + if (_onReceive) { + _onReceive(packetLength); + } + + // reset FIFO address + writeRegister(REG_FIFO_ADDR_PTR, 0); +} + uint8_t ISR_VECT LoRaClass::readRegister(uint8_t address) { return singleTransfer(address & 0x7f, 0x00); @@ -636,7 +796,9 @@ void LoRaClass::writeRegister(uint8_t address, uint8_t value) uint8_t ISR_VECT LoRaClass::singleTransfer(uint8_t address, uint8_t value) { uint8_t response; - + +#if LIBRARY_TYPE == LIBRARY_ARDUINO + // Select chip, send address, and send/read data, the Arduino way digitalWrite(_ss, LOW); SPI.beginTransaction(_spiSettings); @@ -645,6 +807,55 @@ uint8_t ISR_VECT LoRaClass::singleTransfer(uint8_t address, uint8_t value) SPI.endTransaction(); digitalWrite(_ss, HIGH); +#elif LIBRARY_TYPE == LIBRARY_C + // Select chip, send address, and send/read data, the Linux way + + // In Linux, chip select is automatically turned off outside of transactions. + + int status; + + if (_fd <= 0) { + throw std::runtime_error("Accessing SPI device without begin()!"); + } + + // Configure SPI speed and mode to match settings + status = ioctl(_fd, SPI_IOC_WR_MODE, &_spiSettings.mode); + if (status < 0) { + perror("ioctl SPI_IOC_WR_MODE failed"); + exit(1); + } + status = ioctl(_fd, SPI_IOC_WR_LSB_FIRST, &_spiSettings.bitness); + if (status < 0) { + perror("ioctl SPI_IOC_WR_LSB_FIRST failed"); + exit(1); + } + status = ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &_spiSettings.frequency); + if (status < 0) { + perror("ioctl SPI_IOC_WR_MAX_SPEED_HZ failed"); + exit(1); + } + + // We have two transfers: one send-only to send the address, and one + // send/receive, to send the value and get the response. + struct spi_ioc_transfer xfer[2]; + memset(xfer, 0, sizeof xfer); + + xfer[0].tx_buf = (unsigned long) &address; + xfer[0].len = 1; + + xfer[1].tx_buf = (unsigned long) &value; + xfer[1].rx_buf = (unsigned long) &response; + xfer[1].len = 1; + + // Do the transaction + status = ioctl(_fd, SPI_IOC_MESSAGE(2), xfer); + if (status < 0) { + perror("ioctl SPI_IOC_MESSAGE failed"); + exit(1); + } +#else + #error "SPI transfer not implemented for library type" +#endif return response; } @@ -654,4 +865,4 @@ void ISR_VECT LoRaClass::onDio0Rise() LoRa.handleDio0Rise(); } -LoRaClass LoRa; \ No newline at end of file +LoRaClass LoRa; diff --git a/LoRa.h b/LoRa.h index 09bdc54..f67651e 100644 --- a/LoRa.h +++ b/LoRa.h @@ -7,8 +7,38 @@ #ifndef LORA_H #define LORA_H -#include -#include +#include "Platform.h" + +#if LIBRARY_TYPE == LIBRARY_ARDUINO + #include + #include +#elif LIBRARY_TYPE == LIBRARY_C + #include + #include + #include + + // Arduino Stream is not available, but not actually needed. + class Stream {}; + + typedef unsigned char byte; + + // Arduino SPI is not available, so make a Linux-ish version of SPISettings + #define MSBFIRST 0 + #define LSBFIRST 1 + #define SPI_MODE0 SPI_MODE_0 + #define SPI_MODE1 SPI_MODE_1 + #define SPI_MODE2 SPI_MODE_2 + #define SPI_MODE3 SPI_MODE_3 + class SPISettings { + public: + inline SPISettings(uint32_t frequency, byte bitness, byte mode) : frequency(frequency), bitness(bitness), mode(mode) {}; + SPISettings& operator=(const SPISettings& other) = default; + uint32_t frequency; + byte bitness; + byte mode; + }; + +#endif #define LORA_DEFAULT_SS_PIN 10 #define LORA_DEFAULT_RESET_PIN 9 @@ -46,6 +76,7 @@ public: virtual int peek(); virtual void flush(); + void pollReceive(); void onReceive(void(*callback)(int)); void receive(int size = 0); @@ -73,14 +104,21 @@ public: void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN); void setSPIFrequency(uint32_t frequency); - + +#if LIBRARY_TYPE == LIBRARY_ARDUINO void dumpRegisters(Stream& out); +#elif LIBRARY_TYPE == LIBRARY_C + void dumpRegisters(std::ostream& out); +#endif private: + bool resetModem(); + void explicitHeaderMode(); void implicitHeaderMode(); void handleDio0Rise(); + void handleRx(); uint8_t readRegister(uint8_t address); void writeRegister(uint8_t address, uint8_t value); @@ -99,8 +137,12 @@ private: int _packetIndex; int _implicitHeaderMode; void (*_onReceive)(int); + bool _spiBegun; + #if LIBRARY_TYPE == LIBRARY_C + int _fd; + #endif }; extern LoRaClass LoRa; -#endif \ No newline at end of file +#endif diff --git a/MD5.cpp b/MD5.cpp index 56daa77..c04efc1 100644 --- a/MD5.cpp +++ b/MD5.cpp @@ -1,5 +1,11 @@ #include "MD5.h" +#if LIBRARY_TYPE == LIBRARY_ARDUINO + #include +#elif LIBRARY_TYPE == LIBRARY_C + #include +#endif + MD5::MD5() { //nothing @@ -298,4 +304,4 @@ unsigned char* MD5::make_hash(char *arg,size_t size) MD5Update(&context, arg, size); MD5Final(hash, &context); return hash; -} \ No newline at end of file +} diff --git a/MD5.h b/MD5.h index 3ec8d81..3c6a5f4 100644 --- a/MD5.h +++ b/MD5.h @@ -1,7 +1,7 @@ #ifndef MD5_h #define MD5_h -#include "Arduino.h" +#include "Platform.h" /* * This is an OpenSSL-compatible implementation of the RSA Data Security, @@ -49,4 +49,4 @@ public: static void MD5Update(void *ctxBuf, const void *data, size_t size); }; -#endif \ No newline at end of file +#endif diff --git a/Makefile b/Makefile index 7e3e416..eebc832 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,6 @@ prep-samd: arduino-cli core update-index --config-file arduino-cli.yaml arduino-cli core install adafruit:samd - - firmware: arduino-cli compile --fqbn unsignedio:avr:rnode @@ -135,3 +133,25 @@ release-mega2560: arduino-cli compile --fqbn arduino:avr:mega -e cp build/arduino.avr.mega/RNode_Firmware.ino.hex Release/rnode_firmware_latest_m2560.hex rm -r build + +clean: + rm -Rf bin + rm -Rf obj + +CFLAGS += -g + +obj/MD5.o: MD5.cpp MD5.h Platform.h + mkdir -p obj + $(CC) $(CFLAGS) -c -o $@ $< + +obj/LoRa.o: LoRa.cpp LoRa.h Platform.h + mkdir -p obj + $(CC) $(CFLAGS) -c -o $@ $< + +obj/RNode_Firmware.o: RNode_Firmware.ino Utilities.h Config.h LoRa.h ROM.h Framing.h MD5.h Platform.h + mkdir -p obj + $(CC) $(CFLAGS) -c -o $@ -x c++ $< + +bin/rnode: obj/RNode_Firmware.o obj/LoRa.o obj/MD5.o + mkdir -p bin + $(CC) $(CFLAGS) -o $@ $^ -lstdc++ -lutil diff --git a/Platform.h b/Platform.h new file mode 100644 index 0000000..5a4c58c --- /dev/null +++ b/Platform.h @@ -0,0 +1,42 @@ +#ifndef PLATFORM_H +#define PLATFORM_H + +// Determine the platform, MCU, and C library we are building for. + +#define PLATFORM_AVR 0x90 +#define PLATFORM_ESP32 0x80 +#define PLATFORM_LINUX 0x70 + +#define MCU_1284P 0x91 +#define MCU_2560 0x92 +#define MCU_ESP32 0x81 +#define MCU_LINUX 0x71 + +#define LIBRARY_ARDUINO 0x1 +#define LIBRARY_C 0x2 + +#if defined(__AVR_ATmega1284P__) + #define PLATFORM PLATFORM_AVR + #define MCU_VARIANT MCU_1284P + #define LIBRARY_TYPE LIBRARY_ARDUINO +#elif defined(__AVR_ATmega2560__) + #define PLATFORM PLATFORM_AVR + #define MCU_VARIANT MCU_2560 + #define LIBRARY_TYPE LIBRARY_ARDUINO +#elif defined(ESP32) + #define PLATFORM PLATFORM_ESP32 + #define MCU_VARIANT MCU_ESP32 + #define LIBRARY_TYPE LIBRARY_ARDUINO +#elif defined(__unix__) + #define PLATFORM PLATFORM_LINUX + #define MCU_VARIANT MCU_LINUX + #define LIBRARY_TYPE LIBRARY_C +#else + #error "The firmware cannot be compiled for the selected MCU variant" +#endif + +#ifndef MCU_VARIANT + #error No MCU variant defined, cannot compile +#endif + +#endif diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index ea1c90c..aca87b4 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -20,8 +20,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include +#include "Platform.h" + +#if LIBRARY_TYPE == LIBRARY_ARDUINO + #include + #include +#endif #include "Utilities.h" FIFOBuffer serialFIFO; @@ -47,15 +51,26 @@ char sbuf[128]; bool packet_ready = false; #endif +// Arduino C doesn't need pre-declarations to call functions that appear later, +// but standard C does. +void serial_interrupt_init(); +void validateStatus(); +void update_radio_lock(); +void transmit(uint16_t size); +void buffer_serial(); +void serial_poll(); + + void setup() { #if MCU_VARIANT == MCU_ESP32 delay(500); - EEPROM.begin(EEPROM_SIZE); - Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE); #endif + eeprom_open(EEPROM_SIZE); - // Seed the PRNG - randomSeed(analogRead(0)); + #if LIBRARY_TYPE == LIBRARY_ARDUINO + // Seed the PRNG + randomSeed(analogRead(0)); + #endif // Initialise serial communication memset(serialBuffer, 0, sizeof(serialBuffer)); @@ -63,12 +78,18 @@ void setup() { Serial.begin(serial_baudrate); while (!Serial); + + #if MCU_VARIANT == MCU_ESP32 + Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE); + #endif serial_interrupt_init(); - // Configure input and output pins - pinMode(pin_led_rx, OUTPUT); - pinMode(pin_led_tx, OUTPUT); + #if LIBRARY_TYPE == LIBRARY_ARDUINO + // Configure input and output pins + pinMode(pin_led_rx, OUTPUT); + pinMode(pin_led_tx, OUTPUT); + #endif // Initialise buffers memset(pbuf, 0, sizeof(pbuf)); @@ -130,6 +151,9 @@ inline void getPacketData(uint16_t len) { } void ISR_VECT receive_callback(int packet_size) { +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Got packet of " << packet_size << " bytes" << std::endl; +#endif if (!promisc) { // The standard operating mode allows large // packets with a payload up to 500 bytes, @@ -144,6 +168,11 @@ void ISR_VECT receive_callback(int packet_size) { // This is the first part of a split // packet, so we set the seq variable // and add the data to the buffer + +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "\tIs first part of split packet" << std::endl; +#endif + read_len = 0; seq = sequence; @@ -158,7 +187,11 @@ void ISR_VECT receive_callback(int packet_size) { // This is the second part of a split // packet, so we add it to the buffer // and set the ready flag. - + +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "\tIs second part of split packet" << std::endl; +#endif + #if MCU_VARIANT != MCU_ESP32 last_rssi = (last_rssi+LoRa.packetRssi())/2; last_snr_raw = (last_snr_raw+LoRa.packetSnrRaw())/2; @@ -173,6 +206,11 @@ void ISR_VECT receive_callback(int packet_size) { // same sequence id, so we must assume // that we are seeing the first part of // a new split packet. + +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "\tIs first part of a different split packet" << std::endl; +#endif + read_len = 0; seq = sequence; @@ -188,6 +226,10 @@ void ISR_VECT receive_callback(int packet_size) { // just read it and set the ready // flag to true. +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "\tIs complete packet" << std::endl; +#endif + if (seq != SEQ_UNSET) { // If we already had part of a split // packet in the buffer, we clear it. @@ -318,7 +360,7 @@ void flushQueue(void) { uint16_t processed = 0; - #if MCU_VARIANT == MCU_ESP32 + #if SERIAL_EVENTS == SERIAL_POLLING while (!fifo16_isempty(&packet_starts)) { #else while (!fifo16_isempty_locked(&packet_starts)) { @@ -347,6 +389,9 @@ void flushQueue(void) { void transmit(uint16_t size) { if (radio_online) { if (!promisc) { +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Sending RNode packet(s) of " << size << " bytes" << std::endl; +#endif led_tx_on(); uint16_t written = 0; uint8_t header = random(256) & 0xF0; @@ -379,6 +424,11 @@ void transmit(uint16_t size) { // In promiscuous mode, we only send out // plain raw LoRa packets with a maximum // payload of 255 bytes + +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Sending standard packet of " << size << " bytes" << std::endl; +#endif + led_tx_on(); uint16_t written = 0; @@ -683,13 +733,19 @@ void validateStatus() { uint8_t F_WDR = WDRF; #elif MCU_VARIANT == MCU_2560 uint8_t boot_flags = OPTIBOOT_MCUSR; - if (boot_flags == 0x00) boot_flags = 0x03; + if (boot_flags == 0x00) boot_flags = START_FROM_BROWNOUT; uint8_t F_POR = PORF; uint8_t F_BOR = BORF; uint8_t F_WDR = WDRF; #elif MCU_VARIANT == MCU_ESP32 // TODO: Get ESP32 boot flags - uint8_t boot_flags = 0x02; + uint8_t boot_flags = START_FROM_POWERON; + uint8_t F_POR = 0x00; + uint8_t F_BOR = 0x00; + uint8_t F_WDR = 0x01; + #elif MCU_VARIANT == MCU_LINUX + // Linux build always works like a clean boot. + uint8_t boot_flags = START_FROM_POWERON; uint8_t F_POR = 0x00; uint8_t F_BOR = 0x00; uint8_t F_WDR = 0x01; @@ -702,12 +758,12 @@ void validateStatus() { } else if (boot_flags & (1< 0) { if (!dcd_waiting) updateModemStatus(); @@ -775,7 +842,7 @@ void loop() { } } - #if MCU_VARIANT == MCU_ESP32 + #if SERIAL_EVENTS == SERIAL_POLLING buffer_serial(); if (!fifo_isempty(&serialFIFO)) serial_poll(); #else @@ -787,7 +854,7 @@ volatile bool serial_polling = false; void serial_poll() { serial_polling = true; - #if MCU_VARIANT != MCU_ESP32 + #if SERIAL_EVENTS == SERIAL_INTERRUPT while (!fifo_isempty_locked(&serialFIFO)) { #else while (!fifo_isempty(&serialFIFO)) { @@ -812,7 +879,7 @@ void buffer_serial() { while (c < MAX_CYCLES && Serial.available()) { c++; - #if MCU_VARIANT != MCU_ESP32 + #if SERIAL_EVENTS == SERIAL_INTERRUPT if (!fifo_isfull_locked(&serialFIFO)) { fifo_push_locked(&serialFIFO, Serial.read()); } @@ -853,8 +920,8 @@ void serial_interrupt_init() { TIMSK3 = _BV(ICIE3); - #elif MCU_VARIANT == MCU_ESP32 - // No interrupt-based polling on ESP32 + #else + // No interrupt-based polling on other MCUs. #endif } @@ -864,3 +931,12 @@ void serial_interrupt_init() { buffer_serial(); } #endif + +#if PLATFORM == PLATFORM_LINUX + int main(int argc, char** argv) { + setup(); + while (true) { + loop(); + } + } +#endif diff --git a/Utilities.h b/Utilities.h index 5b59364..c0d6813 100644 --- a/Utilities.h +++ b/Utilities.h @@ -1,4 +1,6 @@ -#include +#if LIBRARY_TYPE == LIBRARY_ARDUINO + #include +#endif #include #include "Config.h" #include "LoRa.h" @@ -6,6 +8,143 @@ #include "Framing.h" #include "MD5.h" +#if LIBRARY_TYPE == LIBRARY_C + #include + #include + #include + #include + #include + #include + #include + // We need a delay() + void delay(int ms) { + struct timespec interval; + interval.tv_sec = ms / 1000; + interval.tv_nsec = (ms % 1000) * 1000 * 1000; + // TODO: handle signals interrupting sleep + nanosleep(&interval, NULL); + } + + // And millis() + struct timespec millis_base; + uint32_t millis() { + // Time since first call is close enough. + static bool base_set(false); + if (!base_set) { + if (clock_gettime(CLOCK_MONOTONIC, &millis_base)) { + perror("Could not get time"); + exit(1); + } + base_set = true; + } + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now)) { + perror("Could not get time"); + exit(1); + } + return (now.tv_sec - millis_base.tv_sec) * 1000 + (now.tv_nsec - millis_base.tv_nsec)/(1000*1000); + } + + // Serial will want to poll the EEPROM a bit for help text + bool eeprom_info_locked(); + + // We also need a Serial + class SerialClass { + public: + void begin(int baud) { + // Need to be rrentrant for restart + if (_fd <= 0) { + int other_end = 0; + int status = openpty(&_fd, &other_end, NULL, NULL, NULL); + if (status) { + perror("could not open PTY"); + exit(1); + } + + std::cerr << "Listening on " << ttyname(other_end) << std::endl; + if (!eeprom_info_locked()) { + std::cerr << "EEPROM configuration is not initialized. You will want to flash it with something like:" << std::endl; + std::cerr << "\trnodeconf --key" << std::endl; + std::cerr << "\trnodeconf --rom --platform " << std::hex << PLATFORM << " --product " << PRODUCT_HMBRW << " --model " << MODEL_FF << std::dec << " --hwrev 1 " << ttyname(other_end) << std::endl; + } + } else { + std::cerr << "Skipping Serial reinitialization" << std::endl; + } + } + + operator bool() { + return _fd > 0; + } + void write(int b) { + uint8_t to_write = b; + ssize_t written = ::write(_fd, &to_write, 1); + while (written != 1) { + if (written < 0) { + perror("could not write to PTY"); + exit(1); + } + written = ::write(_fd, &to_write, 1); + } + } + void write(const char* data) { + while(*data) { + write(*data); + ++data; + } + } + bool available() { + struct pollfd request; + request.fd = _fd; + request.events = POLLIN; + request.revents = 0; + + int result = poll(&request, 1, 0); + + if (result == -1) { + perror("could not poll"); + exit(1); + } + + return result > 0; + } + uint8_t read() { + uint8_t buffer; + ssize_t count = ::read(_fd, &buffer, 1); + while (count != 1) { + if (count < 0) { + perror("could not read from PTY"); + exit(1); + } + count = ::read(_fd, &buffer, 1); + } + return buffer; + } + protected: + int _fd; + }; + + + SerialClass Serial; + + // And random(below); + int random(int below) { + return rand() % below; + } + + +#endif + +// Log a debug message. Message should have a \r to return the cursor, if +// needed. +void debug(const char* message) { + #if LIBRARY_TYPE == LIBRARY_C + std::cerr << message << std::endl; + #endif + if (Serial) { + Serial.write(message); + } +} + #if MCU_VARIANT == MCU_ESP32 #include "soc/rtc_wdt.h" #define ISR_VECT IRAM_ATTR @@ -68,7 +207,18 @@ uint8_t boot_vector = 0x00; void led_rx_off() { digitalWrite(pin_led_rx, LOW); } void led_tx_on() { digitalWrite(pin_led_tx, HIGH); } void led_tx_off() { digitalWrite(pin_led_tx, LOW); } - #endif + #endif +#elif MCU_VARIANT == MCU_LINUX + // No LEDs on Linux, probably. SPI only. + void led_rx_on() { } + void led_rx_off() { } + void led_tx_on() { } + void led_tx_off() { } +#endif + +#if LIBRARY_TYPE == LIBRARY_C + // hard_reset needs a declaration for main + int main(int argc, char** argv); #endif void hard_reset(void) { @@ -79,27 +229,39 @@ void hard_reset(void) { } #elif MCU_VARIANT == MCU_ESP32 ESP.restart(); + #elif MCU_VARIANT == MCU_LINUX + // TODO: re-exec ourselves? + #if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Restarting" << std::endl; + exit(main(0, NULL)); + #endif #endif } void led_indicate_error(int cycles) { +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Indicating error" << std::endl; +#endif bool forever = (cycles == 0) ? true : false; cycles = forever ? 1 : cycles; - while(cycles > 0) { - digitalWrite(pin_led_rx, HIGH); - digitalWrite(pin_led_tx, LOW); - delay(100); - digitalWrite(pin_led_rx, LOW); - digitalWrite(pin_led_tx, HIGH); - delay(100); - if (!forever) cycles--; - } - led_rx_off(); + while(cycles > 0) { + led_rx_on(); led_tx_off(); + delay(100); + led_rx_off(); + led_tx_on(); + delay(100); + if (!forever) cycles--; + } + led_rx_off(); + led_tx_off(); } void led_indicate_boot_error() { - while (true) { +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Indicating boot error" << std::endl; +#endif + while (true) { led_tx_on(); led_rx_off(); delay(10); @@ -110,9 +272,12 @@ void led_indicate_boot_error() { } void led_indicate_warning(int cycles) { +#if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Indicating warning" << std::endl; +#endif bool forever = (cycles == 0) ? true : false; cycles = forever ? 1 : cycles; - digitalWrite(pin_led_tx, HIGH); + led_tx_on(); while(cycles > 0) { led_tx_off(); delay(100); @@ -123,7 +288,7 @@ void led_indicate_warning(int cycles) { led_tx_off(); } -#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 +#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 || MCU_VARIANT == MCU_LINUX void led_indicate_info(int cycles) { bool forever = (cycles == 0) ? true : false; cycles = forever ? 1 : cycles; @@ -165,6 +330,9 @@ void led_indicate_warning(int cycles) { } #else void led_indicate_info(int cycles) { + #if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Indicating info" << std::endl; + #endif bool forever = (cycles == 0) ? true : false; cycles = forever ? 1 : cycles; while(cycles > 0) { @@ -179,8 +347,9 @@ void led_indicate_warning(int cycles) { #endif #endif - -unsigned long led_standby_ticks = 0; +#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 || MCU_VARIANT == MCU_ESP32 + unsigned long led_standby_ticks = 0; +#endif #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 uint8_t led_standby_min = 1; uint8_t led_standby_max = 40; @@ -196,8 +365,10 @@ unsigned long led_standby_ticks = 0; unsigned long led_standby_wait = 1768; unsigned long led_notready_wait = 150; #endif -uint8_t led_standby_value = led_standby_min; -int8_t led_standby_direction = 0; +#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 || MCU_VARIANT == MCU_ESP32 + uint8_t led_standby_value = led_standby_min; + int8_t led_standby_direction = 0; +#endif #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 void led_indicate_standby() { @@ -243,6 +414,17 @@ int8_t led_standby_direction = 0; #endif } } +#elif MCU_VARIANT == MCU_LINUX + // No LEDs available. + void led_indicate_standby() { + #if LIBRARY_TYPE == LIBRARY_C + static bool printed = false; + if (!printed) { + std::cerr << "Indicating standby" << std::endl; + printed = true; + } + #endif + } #endif #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 @@ -289,6 +471,17 @@ int8_t led_standby_direction = 0; #endif } } +#elif MCU_VARIANT == MCU_LINUX + // No LEDs available. + void led_indicate_not_ready() { + #if LIBRARY_TYPE == LIBRARY_C + static bool printed = false; + if (!printed) { + std::cerr << "Indicating not ready" << std::endl; + printed = true; + } + #endif + } #endif void escapedSerialWrite(uint8_t byte) { @@ -551,8 +744,68 @@ void promisc_disable() { promisc = false; } +#if MCU_VARIANT == MCU_LINUX + // On Linux we always use memory-mapped EEPROM + uint8_t* eeprom_mapping = NULL; +#endif +#if LIBRARY_TYPE == LIBRARY_C + // And when using the C library we set it up from a file descriptor. + int eeprom_fd = 0; +#endif + +void eeprom_open(int size) { + #if MCU_VARIANT == MCU_ESP32 + // This MCU needs EEPROIM to be begun + EEPROM.begin(size); + #elif MCU_VARIANT == MCU_LINUX + // We need to use file-backed EEPROM emulation + #if LIBRARY_TYPE == LIBRARY_C + const char* eeprom_filename = "eeprom.dat"; + // We need to be reentrant for restarts + if (eeprom_fd <= 0) { + eeprom_fd = open(eeprom_filename, O_RDWR | O_CREAT, 0644); + if (eeprom_fd <= 0) { + perror("Could not open EEPROM file"); + exit(1); + } + int status = ftruncate(eeprom_fd, size); + if (status != 0) { + perror("Could not set size of EEPROM file"); + exit(1); + } + // Map EEPROM into RAM + eeprom_mapping = (uint8_t*) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, eeprom_fd, 0); + if (eeprom_mapping == NULL) { + perror("Could not map EEPROM file"); + exit(1); + } + std::cerr << "Mapped " << eeprom_filename << " as FD " << eeprom_fd << " to address " << (void*)eeprom_mapping << " size " << size << std::endl; + } else { + std::cerr << "Skipping EEPROM reinitialization" << std::endl; + } + #endif + #endif +} + +uint8_t eeprom_read(uint8_t addr) { + #if MCU_VARIANT == MCU_LINUX + if (!eeprom_mapping) { + throw std::runtime_error("Tried to read EEPROM before opening it!"); + } + int mapped_address = eeprom_addr(addr); + return eeprom_mapping[mapped_address]; + #else + return EEPROM.read(eeprom_addr(addr)); + #endif +} + bool eeprom_info_locked() { - uint8_t lock_byte = EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)); + #if MCU_VARIANT == MCU_LINUX + if (!eeprom_mapping) { + return false; + } + #endif + uint8_t lock_byte = eeprom_read(ADDR_INFO_LOCK); if (lock_byte == INFO_LOCK_BYTE) { return true; } else { @@ -560,34 +813,6 @@ bool eeprom_info_locked() { } } -void eeprom_dump_info() { - for (int addr = ADDR_PRODUCT; addr <= ADDR_INFO_LOCK; addr++) { - uint8_t byte = EEPROM.read(eeprom_addr(addr)); - escapedSerialWrite(byte); - } -} - -void eeprom_dump_config() { - for (int addr = ADDR_CONF_SF; addr <= ADDR_CONF_OK; addr++) { - uint8_t byte = EEPROM.read(eeprom_addr(addr)); - escapedSerialWrite(byte); - } -} - -void eeprom_dump_all() { - for (int addr = 0; addr < EEPROM_RESERVED; addr++) { - uint8_t byte = EEPROM.read(eeprom_addr(addr)); - escapedSerialWrite(byte); - } -} - -void kiss_dump_eeprom() { - Serial.write(FEND); - Serial.write(CMD_ROM_READ); - eeprom_dump_all(); - Serial.write(FEND); -} - void eeprom_update(int mapped_addr, uint8_t byte) { #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560 EEPROM.update(mapped_addr, byte); @@ -596,8 +821,12 @@ void eeprom_update(int mapped_addr, uint8_t byte) { EEPROM.write(mapped_addr, byte); EEPROM.commit(); } + #elif MCU_VARIANT == MCU_LINUX + if (!eeprom_mapping) { + throw std::runtime_error("Tried to write EEPROM before opening it!"); + } + eeprom_mapping[mapped_addr] = byte; #endif - } void eeprom_write(uint8_t addr, uint8_t byte) { @@ -615,32 +844,57 @@ void eeprom_erase() { hard_reset(); } -bool eeprom_lock_set() { - if (EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)) == INFO_LOCK_BYTE) { - return true; - } else { - return false; +void eeprom_dump_info() { + for (int addr = ADDR_PRODUCT; addr <= ADDR_INFO_LOCK; addr++) { + uint8_t byte = eeprom_read(addr); + escapedSerialWrite(byte); } } +void eeprom_dump_config() { + for (int addr = ADDR_CONF_SF; addr <= ADDR_CONF_OK; addr++) { + uint8_t byte = eeprom_read(addr); + escapedSerialWrite(byte); + } +} + +void eeprom_dump_all() { + for (int addr = 0; addr < EEPROM_RESERVED; addr++) { + uint8_t byte = eeprom_read(addr); + escapedSerialWrite(byte); + } +} + +void kiss_dump_eeprom() { + Serial.write(FEND); + Serial.write(CMD_ROM_READ); + eeprom_dump_all(); + Serial.write(FEND); +} + bool eeprom_product_valid() { - uint8_t rval = EEPROM.read(eeprom_addr(ADDR_PRODUCT)); + uint8_t rval = eeprom_read(ADDR_PRODUCT); #if PLATFORM == PLATFORM_AVR if (rval == PRODUCT_RNODE || rval == PRODUCT_HMBRW) { #elif PLATFORM == PLATFORM_ESP32 if (rval == PRODUCT_RNODE || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21) { - #else + #elif PLATFORM == PLATFORM_LINUX + if (rval == PRODUCT_HMBRW) { + #else if (false) { #endif return true; } else { + #if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Unacceptable platform: " << std::hex << "0x" << (int)rval << std::dec << std::endl; + #endif return false; } } bool eeprom_model_valid() { - model = EEPROM.read(eeprom_addr(ADDR_MODEL)); + model = eeprom_read(ADDR_MODEL); #if BOARD_MODEL == BOARD_RNODE if (model == MODEL_A4 || model == MODEL_A9) { #elif BOARD_MODEL == BOARD_HMBRW @@ -660,15 +914,21 @@ bool eeprom_model_valid() { #endif return true; } else { + #if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Unacceptable model: " << std::hex << "0x" << (int)model << std::dec << std::endl; + #endif return false; } } bool eeprom_hwrev_valid() { - hwrev = EEPROM.read(eeprom_addr(ADDR_HW_REV)); + hwrev = eeprom_read(ADDR_HW_REV); if (hwrev != 0x00 && hwrev != 0xFF) { return true; } else { + #if LIBRARY_TYPE == LIBRARY_C + std::cerr << "Unacceptable revision: " << std::hex << "0x" << (int)hwrev << std::dec << std::endl; + #endif return false; } } @@ -676,14 +936,14 @@ bool eeprom_hwrev_valid() { bool eeprom_checksum_valid() { char *data = (char*)malloc(CHECKSUMMED_SIZE); for (uint8_t i = 0; i < CHECKSUMMED_SIZE; i++) { - char byte = EEPROM.read(eeprom_addr(i)); + char byte = eeprom_read(i); data[i] = byte; } unsigned char *hash = MD5::make_hash(data, CHECKSUMMED_SIZE); bool checksum_valid = true; for (uint8_t i = 0; i < 16; i++) { - uint8_t stored_chk_byte = EEPROM.read(eeprom_addr(ADDR_CHKSUM+i)); + uint8_t stored_chk_byte = eeprom_read(ADDR_CHKSUM+i); uint8_t calced_chk_byte = (uint8_t)hash[i]; if (stored_chk_byte != calced_chk_byte) { checksum_valid = false; @@ -696,7 +956,7 @@ bool eeprom_checksum_valid() { } bool eeprom_have_conf() { - if (EEPROM.read(eeprom_addr(ADDR_CONF_OK)) == CONF_OK_BYTE) { + if (eeprom_read(ADDR_CONF_OK) == CONF_OK_BYTE) { return true; } else { return false; @@ -705,11 +965,11 @@ bool eeprom_have_conf() { void eeprom_conf_load() { if (eeprom_have_conf()) { - lora_sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF)); - lora_cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR)); - lora_txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP)); - lora_freq = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x03); - lora_bw = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x03); + lora_sf = eeprom_read(ADDR_CONF_SF); + lora_cr = eeprom_read(ADDR_CONF_CR); + lora_txp = eeprom_read(ADDR_CONF_TXP); + lora_freq = (uint32_t)eeprom_read(ADDR_CONF_FREQ+0x00) << 24 | (uint32_t)eeprom_read(ADDR_CONF_FREQ+0x01) << 16 | (uint32_t)eeprom_read(ADDR_CONF_FREQ+0x02) << 8 | (uint32_t)eeprom_read(ADDR_CONF_FREQ+0x03); + lora_bw = (uint32_t)eeprom_read(ADDR_CONF_BW+0x00) << 24 | (uint32_t)eeprom_read(ADDR_CONF_BW+0x01) << 16 | (uint32_t)eeprom_read(ADDR_CONF_BW+0x02) << 8 | (uint32_t)eeprom_read(ADDR_CONF_BW+0x03); } } @@ -784,7 +1044,7 @@ inline void fifo_flush(FIFOBuffer *f) { f->head = f->tail; } -#if MCU_VARIANT != MCU_ESP32 +#if SERIAL_EVENTS == SERIAL_INTERRUPT static inline bool fifo_isempty_locked(const FIFOBuffer *f) { bool result; ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { @@ -866,7 +1126,7 @@ inline void fifo16_flush(FIFOBuffer16 *f) { f->head = f->tail; } -#if MCU_VARIANT != MCU_ESP32 +#if SERIAL_EVENTS == SERIAL_INTERRUPT static inline bool fifo16_isempty_locked(const FIFOBuffer16 *f) { bool result; ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {