diff --git a/lib/comms/bus.cpp b/lib/comms/bus.cpp new file mode 100644 index 0000000..520aa58 --- /dev/null +++ b/lib/comms/bus.cpp @@ -0,0 +1,92 @@ +#include "bus.h" +#include + +bool initUARTs(Config &config) +{ + if (config.uart0.enabled) + { + Uart0.end(); + Uart0.begin(config.uart0.clock_freq, SERIAL_8N1, config.uart0.rx, + config.uart0.tx); + } + + if (config.uart1.enabled) + { + Uart1.end(); + Uart1.begin(config.uart1.clock_freq, SERIAL_8N1, config.uart1.rx, + config.uart1.tx); + } + + return true; +} + +SPIClass &hspi = *(new SPIClass(HSPI)); // not usable until initSPIs + +bool initSPIs(Config &config) +{ + if (config.spi1.enabled) + { + delete (&hspi); + hspi = *(new SPIClass(config.spi1.bus_num)); + if (config.spi1.clock_freq > 0) + { + hspi.setFrequency(config.spi1.clock_freq); + } + + // if all the pins are -1, then will use the default for SPI bus_num + hspi.begin(config.spi1.clk, config.spi1.miso, config.spi1.mosi); + Serial.printf("Initialized SPI%d @ %x: SC:%d MISO:%d MOSI:%d clock:%d\n", + (int)config.spi1.bus_num, (void *)&hspi, (int)config.spi1.clk, + (int)config.spi1.miso, (int)config.spi1.mosi, + (int)config.spi1.clock_freq); + } + + return true; +} + +uint8_t _scanSupportedDevicesOnWire(TwoWire &w, int bus_num); + +uint8_t wireDevices; +uint8_t wire1Devices; + +bool initWires(Config &config) +{ + wireDevices = _scanSupportedDevicesOnWire(Wire, 0); + + if (config.wire1.enabled) + { +#if SOC_I2C_NUM > 1 + // if you want to use default pins, configure -1 + // if you want to use default clock speed, configure 0 + if (!Wire1.begin(config.wire1.sda, config.wire1.scl, config.wire1.clock_freq)) + { + Serial.println("Failed to initialize Wire1"); + return false; + } + + wire1Devices = _scanSupportedDevicesOnWire(Wire1, 1); +#endif + } + + return true; +} + +uint8_t _scanSupportedDevicesOnWire(TwoWire &w, int bus_num) +{ + uint8_t res = 0; + + for (int i = 0; known_i2c_devices[i].address > 0; i++) + { + w.beginTransmission(known_i2c_devices[i].address); + delay(2); + if (w.endTransmission() == 0) + { + Serial.printf("Found supported device on Wire%d: %s(%X)\n", bus_num, + known_i2c_devices[i].name.c_str(), + (int)known_i2c_devices[i].address); + res |= 1 << i; + } + } + + return res; +} diff --git a/lib/comms/bus.h b/lib/comms/bus.h new file mode 100644 index 0000000..b94599e --- /dev/null +++ b/lib/comms/bus.h @@ -0,0 +1,39 @@ +#pragma once +#include + +struct +{ + String name; + uint8_t address; +} known_i2c_devices[] = {{"HMC5883L", 0x1e}, {"QMC5883L", 0x0d}, {" last record ", 0}}; + +enum I2CDevices +{ + // powers of 2 + HMC5883L = 1, + QMC5883L = 2 +}; + +extern uint8_t wireDevices; +extern uint8_t wire1Devices; + +extern SPIClass &hspi; + +// abstract away a reference to Serial vs Serial0 vs Serial1, so it compiles +#ifndef ARDUINO_USB_CDC_ON_BOOT +#define Uart0 Serial +#else +#define Uart0 Serial0 +#endif + +#if SOC_UART_NUM > 1 +#define Uart1 Serial1 +#else +#define Uart1 Uart0 +#endif + +bool initSPIs(Config &config); + +bool initUARTs(Config &config); + +bool initWires(Config &config); diff --git a/lib/comms/comms.cpp b/lib/comms/comms.cpp index b31fe13..c0215d0 100644 --- a/lib/comms/comms.cpp +++ b/lib/comms/comms.cpp @@ -86,9 +86,8 @@ bool Comms::initComms(Config &c) if (c.listen_on_serial0.equalsIgnoreCase("readline")) { // comms using readline plaintext protocol - Comms0 = new ReadlineComms("UART0", SERIAL0); - SERIAL0.onReceive(_onReceive0, false); - SERIAL0.begin(115200); + Comms0 = new ReadlineComms("UART0", Uart0); + Uart0.onReceive(_onReceive0, false); Serial.println("Initialized communications on Serial0 using readline protocol"); } @@ -102,9 +101,8 @@ bool Comms::initComms(Config &c) if (c.listen_on_serial1.equalsIgnoreCase("readline")) { // comms using readline plaintext protocol - Comms1 = new ReadlineComms("UART1", Serial1); - Serial1.onReceive(_onReceive1, false); - Serial1.begin(115200); + Comms1 = new ReadlineComms("UART1", Uart1); + Uart1.onReceive(_onReceive1, false); Serial.println("Initialized communications on Serial1 using readline protocol"); } @@ -420,7 +418,7 @@ String _scan_result_str(ScanTaskResult &r) for (int i = 0; i < r.sz; i++) { p += (i == 0 ? "(" : ", (") + String(r.freqs_khz[i]) + ", " + String(r.rssis[i]) + - ")"; + (r.rssis2 ? ", " + String(r.rssis2[i]) : "") + ")"; } return p + " ]\n"; diff --git a/lib/comms/comms.h b/lib/comms/comms.h index 4154e36..57fb90b 100644 --- a/lib/comms/comms.h +++ b/lib/comms/comms.h @@ -5,14 +5,9 @@ #include #include +#include #include -#ifndef ARDUINO_USB_CDC_ON_BOOT -#define SERIAL0 Serial -#else -#define SERIAL0 Serial0 -#endif - #ifndef SCAN_MAX_RESULT_KHZ_SCALE // kHz scale: round frequency, so it fits into 2 bytes // 2500000 / 40 = 62500, scale 40 fits 2.5GHz into two bytes @@ -56,6 +51,7 @@ struct ScanTaskResult size_t sz; uint32_t *freqs_khz; int16_t *rssis; + int16_t *rssis2; int16_t prssi; }; @@ -135,7 +131,7 @@ struct Comms struct NoopComms : Comms { - NoopComms() : Comms("no-op", SERIAL0) {}; + NoopComms() : Comms("no-op", Uart0) {}; virtual bool send(Message &) { return true; }; virtual void _onReceive() {}; diff --git a/lib/config/config.cpp b/lib/config/config.cpp index 28c8779..3f3d8d9 100644 --- a/lib/config/config.cpp +++ b/lib/config/config.cpp @@ -88,18 +88,6 @@ Config Config::init() continue; } - if (r.key.equalsIgnoreCase("rx_lora")) - { - c.rx_lora = configureLora(r.value); - continue; - } - - if (r.key.equalsIgnoreCase("tx_lora")) - { - c.tx_lora = configureLora(r.value); - continue; - } - Serial.printf("Unknown key '%s' will be ignored\n", r.key); } @@ -170,6 +158,36 @@ bool Config::updateConfig(String key, String value) return true; } + if (key.equalsIgnoreCase("uart0")) + { + uart0 = BusConfig::configure(value); + return true; + } + + if (key.equalsIgnoreCase("uart1")) + { + uart1 = BusConfig::configure(value); + return true; + } + + if (key.equalsIgnoreCase("spi1")) + { + spi1 = BusConfig::configure(value); + return true; + } + + if (key.equalsIgnoreCase("wire1")) + { + wire1 = BusConfig::configure(value); + return true; + } + + if (key.equalsIgnoreCase("radio2")) + { + radio2 = RadioModuleSPIConfig::configure(value); + return true; + } + UPDATE_BOOL(is_host, key, value); UPDATE_BOOL(lora_enabled, key, value); @@ -499,6 +517,102 @@ void Config::configureDetectionStrategy(String cfg) } } +RadioModuleSPIConfig RadioModuleSPIConfig::configure(String cfg) +{ + RadioModuleSPIConfig c; + + c.bus_num = 1; + c.cs = RADIO_MODULE_CS_PIN; + c.rst = RADIO_MODULE_RST_PIN; + c.dio1 = RADIO_MODULE_DIO1_PIN; + c.busy = RADIO_MODULE_BUSY_PIN; + + c.clock_freq = RADIO_MODULE_CLOCK_FREQ; + c.msb_first = RADIO_MODULE_MSB_FIRST; + c.spi_mode = RADIO_MODULE_SPI_MODE; + + int begin = 0; + int end, i; + + while ((i = findSepa(cfg, ",", begin, end)) >= 0) + { + String param = cfg.substring(begin, end); + begin = i; + int j = param.indexOf(":"); + if (j < 0) + { + c.module = param; + c.enabled = !param.equalsIgnoreCase("none"); + continue; + } + + String k = param.substring(0, j); + param = param.substring(j + 1); + + k.toLowerCase(); + if (k.equals("bus")) + { + c.bus_num = param.toInt(); + continue; + } + + if (k.equals("rst")) + { + c.rst = param.toInt(); + continue; + } + + if (k.equals("dio1")) + { + c.dio1 = param.toInt(); + continue; + } + + if (k.equals("busy")) + { + c.busy = param.toInt(); + continue; + } + + if (k.equals("freq")) + { + c.clock_freq = param.toInt(); + continue; + } + + if (k.equals("msb")) + { + c.msb_first = !!param.toInt(); + continue; + } + + if (k.equals("spi_mode")) + { + c.spi_mode = param.toInt(); + continue; + } + + c.module = k; + c.cs = param.toInt(); + c.enabled = true; + } + + return c; +} + +String RadioModuleSPIConfig::toStr() +{ + if (!enabled) + { + return "none"; + } + + return module + ":" + String(cs) + ",bus:" + String(bus_num) + ",rst:" + String(rst) + + ",dio1:" + String(dio1) + ",busy:" + String(busy) + + ",freq:" + String(clock_freq) + ",msb:" + String(msb_first ? 1 : 0) + + ",spi_mode:" + String(spi_mode); +} + bool Config::write_config(const char *path) { File f = SD.open(path, FILE_WRITE, /*create = */ true); @@ -521,6 +635,12 @@ bool Config::write_config(const char *path) f.println("lora_enabled = " + getConfig("lora_enabled")); + f.println("uart0 = " + getConfig("uart0")); + f.println("uart1 = " + getConfig("uart1")); + f.println("spi1 = " + getConfig("spi1")); + f.println("wire1 = " + getConfig("wire1")); + f.println("radio2 = " + getConfig("radio2")); + f.close(); return true; } @@ -572,6 +692,31 @@ String Config::getConfig(String key) return String(is_host ? "true" : "false"); } + if (key.equalsIgnoreCase("uart0")) + { + return uart0.toStr(); + } + + if (key.equalsIgnoreCase("uart1")) + { + return uart1.toStr(); + } + + if (key.equalsIgnoreCase("spi1")) + { + return spi1.toStr(); + } + + if (key.equalsIgnoreCase("wire1")) + { + return wire1.toStr(); + } + + if (key.equalsIgnoreCase("radio2")) + { + return radio2.toStr(); + } + return ""; } @@ -642,3 +787,127 @@ ParseResult parse_config_line(String ln) return ParseResult(k, v); } + +BusConfig BusConfig::configure(String cfg) +{ + BusConfig c; + + if (cfg.equalsIgnoreCase("none")) + { + return c; + } + + int begin = 0; + int end, i; + + while ((i = findSepa(cfg, ",", begin, end)) >= 0) + { + String param = cfg.substring(begin, end); + begin = i; + int j = param.indexOf(":"); + if (j < 0) + { + Serial.printf("Expected ':' to be present in '%s' - ignoring config\n", + param); + continue; + } + + String k = param.substring(0, j); + param = param.substring(j + 1); + + k.toLowerCase(); + if (k.equals("enabled")) + { + c.enabled = !param.equalsIgnoreCase("false"); + continue; + } + + if (c.bus_type == SPI && k.equals("clk") || c.bus_type == WIRE && k.equals("scl")) + { + c.clk = param.toInt(); + continue; + } + + if (c.bus_type == SERIAL && k.equals("tx") || + c.bus_type == SPI && k.equals("mosi") || + c.bus_type == WIRE && k.equals("sda")) + { + c.tx = param.toInt(); + continue; + } + + if (c.bus_type == SERIAL && k.equals("rx") || + c.bus_type == SPI && k.equals("miso")) + { + c.rx = param.toInt(); + continue; + } + + if (c.bus_type != NONE) + { + Serial.printf("Unknown key: '%s'; ignoring config\n", k.c_str()); + continue; + } + + if (k.equals("none") || k.length() == 0) + { + continue; + } + + c.enabled = true; + + char bus_type = k.charAt(0); + switch (bus_type) + { + case 'u': + c.bus_type = UART; + break; + case 's': + c.bus_type = SPI; + break; + case 'w': + c.bus_type = WIRE; + break; + default: + c.bus_type = NONE; + c.enabled = false; + } + + c.bus_num = k.substring(1).toInt(); + c.clock_freq = param.toInt(); + } + + return c; +} + +String BusConfig::toStr() +{ + if (bus_type == NONE) + { + return "none"; + } + + String ret = String(bus_type == UART ? "u" + : bus_type == SPI ? "s" + : bus_type == WIRE ? "w" + : "none") + + String(bus_num); + + ret += ":" + String(clock_freq) + (enabled ? "" : ",enabled:false"); + switch (bus_type) + { + case UART: + ret += ",rx:" + String(rx) + ",tx:" + String(tx); + break; + case SPI: + ret += ",clk:" + String(clk) + ",mosi:" + String(mosi) + ",miso:" + String(miso); + break; + case WIRE: + ret += ",scl:" + String(scl) + ",sda:" + String(sda); + break; + default: + ret = "none"; + } + + return ret; +} diff --git a/lib/config/config.h b/lib/config/config.h index b52e740..4be175c 100644 --- a/lib/config/config.h +++ b/lib/config/config.h @@ -53,6 +53,95 @@ struct LoRaConfig LoRaConfig *configureLora(String cfg); +struct BusConfig +{ + enum + { + NONE, // No bus + UART, // Serial + SPI, + WIRE // I2C + } bus_type; + + int8_t bus_num; + + bool enabled; + + uint32_t clock_freq; + + union + { + int8_t scl; + int8_t clk; + }; + + union + { + int8_t sda; + int8_t mosi; + int8_t tx; + }; + + union + { + int8_t miso; + int8_t rx; + }; + + BusConfig() + : bus_type(NONE), bus_num(-1), enabled(false), clock_freq(115200), clk(-1), + rx(-1), tx(-1) {}; + + static BusConfig configure(String cfg); + String toStr(); +}; + +#ifndef RADIO_MODULE_CS_PIN +#define RADIO_MODULE_CS_PIN 38 +#endif + +#ifndef RADIO_MODULE_DIO1_PIN +#define RADIO_MODULE_DIO1_PIN 40 +#endif + +#ifndef RADIO_MODULE_RST_PIN +#define RADIO_MODULE_RST_PIN 41 +#endif + +#ifndef RADIO_MODULE_BUSY_PIN +#define RADIO_MODULE_BUSY_PIN 39 +#endif + +#ifndef RADIO_MODULE_CLOCK_FREQ +#define RADIO_MODULE_CLOCK_FREQ 16000000 +#endif + +#ifndef RADIO_MODULE_MSB_FIRST +#define RADIO_MODULE_MSB_FIRST 1 +#endif + +#ifndef RADIO_MODULE_SPI_MODE +#define RADIO_MODULE_SPI_MODE 0 +#endif + +struct RadioModuleSPIConfig +{ + bool enabled; + String module; + int8_t bus_num; + int8_t cs; + int8_t rst; + int8_t dio1; + int8_t busy; + + uint32_t clock_freq; + bool msb_first; + int8_t spi_mode; + + static RadioModuleSPIConfig configure(String cfg); + String toStr(); +}; + #ifndef FREQ_RX #define FREQ_RX 866 #endif @@ -84,6 +173,26 @@ LoRaConfig *configureLora(String cfg); #define DEFAULT_LORA_SF 7 #endif +#ifndef DEFAULT_UART0 +#define DEFAULT_UART0 "none" +#endif + +#ifndef DEFAULT_UART1 +#define DEFAULT_UART1 "u1:115200" +#endif + +#ifndef DEFAULT_SPI1 +#define DEFAULT_SPI1 "s1:16000000,clk:42,mosi:46,miso:45" +#endif + +#ifndef DEFAULT_WIRE1 +#define DEFAULT_WIRE1 "none" +#endif + +#ifndef DEFAULT_RADIO2 +#define DEFAULT_RADIO2 "none" +#endif + #define CREATE_MISSING_CONFIG true struct Config { @@ -100,6 +209,12 @@ struct Config LoRaConfig *rx_lora; LoRaConfig *tx_lora; + BusConfig uart0; + BusConfig uart1; + BusConfig spi1; + BusConfig wire1; + RadioModuleSPIConfig radio2; + bool is_host; bool lora_enabled; @@ -110,7 +225,11 @@ struct Config listen_on_serial0(String("none")), listen_on_serial1(String("readline")), listen_on_usb(String("readline")), rx_lora(configureLora(DEFAULT_RX)), tx_lora(configureLora(DEFAULT_TX)), is_host(DEFAULT_IS_LORA_HOST), - lora_enabled(DEFAULT_LORA_ENABLED) {}; + uart0(BusConfig::configure(DEFAULT_UART0)), + uart1(BusConfig::configure(DEFAULT_UART1)), + spi1(BusConfig::configure(DEFAULT_SPI1)), + wire1(BusConfig::configure(DEFAULT_WIRE1)), lora_enabled(DEFAULT_LORA_ENABLED), + radio2(RadioModuleSPIConfig::configure(DEFAULT_RADIO2)) {}; bool write_config(const char *path); diff --git a/lib/events/events.h b/lib/events/events.h index 6f1dea0..b1b249b 100644 --- a/lib/events/events.h +++ b/lib/events/events.h @@ -18,6 +18,7 @@ struct Event struct { float rssi; + float rssi2; float freq; bool trigger; bool detected; diff --git a/lib/heading/Compass.cpp b/lib/heading/Compass.cpp index 3fa5309..8a86871 100644 --- a/lib/heading/Compass.cpp +++ b/lib/heading/Compass.cpp @@ -1,5 +1,4 @@ #include "heading.h" -#include /* * QMC5883L Registers: @@ -62,11 +61,6 @@ bool QMC5883LCompass::begin() { _lastErr = CompassStatus::COMPASS_UNINITIALIZED; - if (!Wire1.begin(46, 42)) /* SDA, SCL */ - { - return false; - } - String err = selfTest(); if (!err.startsWith("OK\n")) { @@ -77,16 +71,17 @@ bool QMC5883LCompass::begin() return true; } -uint8_t _write_register(uint8_t addr, uint8_t reg, uint8_t value, bool skipValue = false) +uint8_t _write_register(TwoWire &wire, uint8_t addr, uint8_t reg, uint8_t value, + bool skipValue = false) { - Wire1.beginTransmission(addr); - size_t s = Wire1.write(reg); + wire.beginTransmission(addr); + size_t s = wire.write(reg); if (s == 1 && !skipValue) { - s = Wire1.write(value); + s = wire.write(value); } - size_t s1 = Wire1.endTransmission(); + size_t s1 = wire.endTransmission(); if (s != 1 && s1 == 0) { return 1; // "data too long to fit in transmit buffer" @@ -95,30 +90,31 @@ uint8_t _write_register(uint8_t addr, uint8_t reg, uint8_t value, bool skipValue return s1; } -int8_t _read_registers(uint8_t addr, uint8_t reg, uint8_t *v, size_t sz, +int8_t _read_registers(TwoWire &wire, uint8_t addr, uint8_t reg, uint8_t *v, size_t sz, bool skipRegister = false) { if (!skipRegister) { - uint8_t s = _write_register(addr, reg, 0, true); + uint8_t s = _write_register(wire, addr, reg, 0, true); if (s != 0) { return s; } } - uint8_t r = Wire1.requestFrom(addr, sz); + uint8_t r = wire.requestFrom(addr, sz); for (int i = 0; i < r; i++, v++) { - *v = Wire1.read(); + *v = wire.read(); } return r - sz; } -uint8_t _read_register(uint8_t addr, uint8_t reg, uint8_t &v, bool skipRegister = false) +uint8_t _read_register(TwoWire &wire, uint8_t addr, uint8_t reg, uint8_t &v, + bool skipRegister = false) { - uint8_t r = _read_registers(addr, reg, &v, 1, skipRegister); + uint8_t r = _read_registers(wire, addr, reg, &v, 1, skipRegister); if (r != 0) { return 1; @@ -127,10 +123,10 @@ uint8_t _read_register(uint8_t addr, uint8_t reg, uint8_t &v, bool skipRegister return 0; } -int8_t _read_xyz(CompassXYZ &xyz) +int8_t _read_xyz(TwoWire &wire, CompassXYZ &xyz) { xyz.status = 0; - size_t s = _read_register(QMC5883_ADDR, QMC5883_STATUS_REG, xyz.status); + size_t s = _read_register(wire, QMC5883_ADDR, QMC5883_STATUS_REG, xyz.status); if (s != 0) { return s; @@ -139,7 +135,7 @@ int8_t _read_xyz(CompassXYZ &xyz) if ((xyz.status & QMC5883_STATUS_DRDY) == 0) { delay(10); - s = _read_register(QMC5883_ADDR, QMC5883_STATUS_REG, xyz.status); + s = _read_register(wire, QMC5883_ADDR, QMC5883_STATUS_REG, xyz.status); if (s != 0) { return s; @@ -148,7 +144,7 @@ int8_t _read_xyz(CompassXYZ &xyz) int16_t mags[3]; - int8_t r = _read_registers(QMC5883_ADDR, 0, (uint8_t *)&mags, 6); + int8_t r = _read_registers(wire, QMC5883_ADDR, 0, (uint8_t *)&mags, 6); xyz.x = mags[0]; xyz.y = mags[1]; xyz.z = mags[1]; @@ -160,8 +156,8 @@ uint8_t QMC5883LCompass::setMode(CompassMode m) { if (m == CompassMode::COMPASS_IDLE) { - uint8_t s = _write_register(QMC5883_ADDR, QMC5883_FBR_REG, 0); - s |= _write_register(QMC5883_ADDR, QMC5883_CTR_REG, 0); + uint8_t s = _write_register(wire, QMC5883_ADDR, QMC5883_FBR_REG, 0); + s |= _write_register(wire, QMC5883_ADDR, QMC5883_CTR_REG, 0); return s; } @@ -185,13 +181,14 @@ uint8_t QMC5883LCompass::setMode(CompassMode m) return 1; } - uint8_t s = _write_register(QMC5883_ADDR, QMC5883_FBR_REG, 1); // set/reset period + uint8_t s = + _write_register(wire, QMC5883_ADDR, QMC5883_FBR_REG, 1); // set/reset period if (s != 0) { return s; } - return _write_register(QMC5883_ADDR, QMC5883_CTR_REG, + return _write_register(wire, QMC5883_ADDR, QMC5883_CTR_REG, (osr << 6) | (rng << 4) | (odr << 2) | mode); } @@ -211,7 +208,7 @@ String QMC5883LCompass::selfTest() for (int i = 0; i < 100; i++) { CompassXYZ xyz; - int8_t r = _read_xyz(xyz); + int8_t r = _read_xyz(wire, xyz); if (r < 0) { errors = true; @@ -238,7 +235,7 @@ String QMC5883LCompass::selfTest() return res; } -int8_t QMC5883LCompass::readXYZ() { return _read_xyz(xyz); } +int8_t QMC5883LCompass::readXYZ() { return _read_xyz(wire, xyz); } int64_t Compass::lastRead() { diff --git a/lib/heading/heading.h b/lib/heading/heading.h index d3bebbb..193faca 100644 --- a/lib/heading/heading.h +++ b/lib/heading/heading.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include struct HeadingSensor @@ -57,7 +58,8 @@ struct Compass : HeadingSensor struct QMC5883LCompass : Compass { - QMC5883LCompass() : Compass() {} + TwoWire &wire; + QMC5883LCompass(TwoWire &wire) : Compass(), wire(wire) {} bool begin() override; String selfTest() override; diff --git a/lib/loraboards/LiLyGo.h b/lib/loraboards/LiLyGo.h index 103240b..2be621b 100644 --- a/lib/loraboards/LiLyGo.h +++ b/lib/loraboards/LiLyGo.h @@ -18,10 +18,10 @@ #ifndef HELTEC_NO_RADIO_INSTANCE #ifndef ARDUINO_heltec_wifi_32_lora_V3 // Assume MISO and MOSI being wrong when not using Heltec's board definition -// and use hspi to make it work anyway. See heltec_setup() for the actual SPI setup. +// and use vspi to make it work anyway. See heltec_setup() for the actual SPI setup. #include -extern SPIClass *hspi; -#define RADIO_MODULE_INIT() new Module(SS, DIO1, RST_LoRa, BUSY_LoRa, *hspi); +extern SPIClass *vspi; +#define RADIO_MODULE_INIT() new Module(SS, DIO1, RST_LoRa, BUSY_LoRa, *vspi); #else // ARDUINO_heltec_wifi_32_lora_V3 #endif // end ARDUINO_heltec_wifi_32_lora_V3 #endif // end HELTEC_NO_RADIO_INSTANCE diff --git a/lib/loraboards/LoRaBoards.cpp b/lib/loraboards/LoRaBoards.cpp index 7353c99..61e515b 100644 --- a/lib/loraboards/LoRaBoards.cpp +++ b/lib/loraboards/LoRaBoards.cpp @@ -77,7 +77,7 @@ void heltec_setup() #ifdef HELTEC #ifndef ARDUINO_heltec_wifi_32_lora_V3 - hspi->begin(SCK, MISO, MOSI, SS); + vspi->begin(SCK, MISO, MOSI, SS); #endif #endif #ifndef HELTEC_NO_DISPLAY_INSTANCE @@ -90,7 +90,7 @@ void heltec_setup() #ifdef HELTEC #ifndef ARDUINO_heltec_wifi_32_lora_V3 -SPIClass hspi = new SPIClass(2); +SPIClass vspi = new SPIClass(2); #endif #endif @@ -533,7 +533,7 @@ bool beginDisplay() Wire.beginTransmission(DISPLAY_ADDR); if (Wire.endTransmission() == 0) { - Serial.printf("Find Display model at 0x%X address\n", DISPLAY_ADDR); + Serial.printf("Found Display model at 0x%X address\n", DISPLAY_ADDR); u8g2 = new DISPLAY_MODEL(U8G2_R0, U8X8_PIN_NONE); u8g2->begin(); u8g2->clearBuffer(); @@ -569,6 +569,7 @@ bool beginSDCard() else { Serial.println("Warning: Failed to init Sd Card"); + SDCardSPI.end(); } #endif return false; @@ -792,10 +793,9 @@ void setupBoards(bool disable_u8g2) bool sdReady; #ifndef DISABLE_SDCARD - for (int i = 0; i < 5 && !(sdReady = beginSDCard()); i++) + if (!(sdReady = beginSDCard())) { Serial.println("SD card failed or not found"); - delay(1000); } #endif diff --git a/lib/radio/SX1262.cpp b/lib/radio/SX1262.cpp new file mode 100644 index 0000000..fe2237b --- /dev/null +++ b/lib/radio/SX1262.cpp @@ -0,0 +1,49 @@ +#include "radio.h" +#include +#include + +SX1262Module::SX1262Module(RadioModuleSPIConfig radio2) : RadioModule() +{ + _radio = new SX1262(new Module( + radio2.cs, radio2.dio1, radio2.rst, radio2.busy, radio2.bus_num == 1 ? hspi : SPI, + SPISettings(radio2.clock_freq, radio2.msb_first ? MSBFIRST : LSBFIRST, + radio2.spi_mode))); + Serial.printf("Initialized Radio2: %s\n", radio2.toStr().c_str()); +} + +int16_t SX1262Module::beginScan(float init_freq, float bw, uint8_t shaping) +{ + int16_t status = _radio->beginFSK(init_freq); + if (status != RADIOLIB_ERR_NONE) + { + Serial.printf("Radio2: Failed beginFSK: %d\n", status); + return status; + } + + status = _radio->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_NONE); + + if (status != RADIOLIB_ERR_NONE) + { + Serial.printf("Radio2: Failed startReceive: %d\n", status); + return status; + } + + status = setFrequency(init_freq); + if (status != RADIOLIB_ERR_NONE) + { + Serial.printf("Radio2: Failed setFrequency: %d\n", status); + return status; + } + + return status; +} + +int16_t SX1262Module::setFrequency(float freq) +{ + return _radio->setFrequency(freq, + true); // false = calibration is needed here +} + +int16_t SX1262Module::setRxBandwidth(float bw) { return _radio->setRxBandwidth(bw); } + +float SX1262Module::getRSSI() { return _radio->getRSSI(false); } diff --git a/lib/radio/radio.h b/lib/radio/radio.h new file mode 100644 index 0000000..81c14a1 --- /dev/null +++ b/lib/radio/radio.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +struct RadioModule +{ + RadioModule() {}; + + virtual int16_t beginScan(float init_freq, float bw, uint8_t shaping) = 0; + virtual int16_t setFrequency(float freq) = 0; + virtual int16_t setRxBandwidth(float bw) = 0; + virtual float getRSSI() = 0; +}; + +#ifdef USING_SX1262 +struct SX1262Module : RadioModule +{ + SX1262 *_radio; + + SX1262Module(RadioModuleSPIConfig cfg); + + int16_t beginScan(float init_freq, float bw, uint8_t shaping) override; + int16_t setFrequency(float freq) override; + int16_t setRxBandwidth(float bw) override; + + float getRSSI() override; +}; +#endif diff --git a/src/main.cpp b/src/main.cpp index 5e69d34..9079f65 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -139,11 +139,15 @@ void sendBTData(float heading, float rssi) #include #endif // end LILYGO +#include #include +#include DroneHeading droneHeading; Compass *compass = NULL; +RadioModule *radio2; + #define BT_SCAN_DELAY 60 * 1 * 1000 #define WF_SCAN_DELAY 60 * 2 * 1000 long noDevicesMillis = 0, cycleCnt = 0; @@ -941,6 +945,25 @@ void init_radio() setFrequency(CONF_FREQ_BEGIN); delay(100); + + if (config.radio2.enabled && config.radio2.module.equalsIgnoreCase("SX1262")) + { + radio2 = new SX1262Module(config.radio2); + state = radio2->beginScan(CONF_FREQ_BEGIN, BANDWIDTH, RADIOLIB_SHAPING_NONE); + if (state == RADIOLIB_ERR_NONE) + { + both.println("Initialized additional module OK"); + radio2->setRxBandwidth(BANDWIDTH); + } + else + { + Serial.printf("Error initializing additional module: %d\n", state); + if (state == RADIOLIB_ERR_CHIP_NOT_FOUND) + { + Serial.println("Radio2: CHIP NOT FOUND"); + } + } + } } struct frequency_scan_result @@ -972,12 +995,19 @@ void eventListenerForReport(void *arg, Event &e) frequency_scan_result.readings_sz = frequency_scan_result.dump.sz + 1; uint32_t *f = new uint32_t[frequency_scan_result.readings_sz]; int16_t *r = new int16_t[frequency_scan_result.readings_sz]; + int16_t *r2 = radio2 ? new int16_t[frequency_scan_result.readings_sz] : NULL; if (old_sz > 0) { memcpy(f, frequency_scan_result.dump.freqs_khz, old_sz * sizeof(uint32_t)); memcpy(r, frequency_scan_result.dump.rssis, old_sz * sizeof(int16_t)); + if (radio2) + { + memcpy(r2, frequency_scan_result.dump.rssis2, + old_sz * sizeof(int16_t)); + delete[] frequency_scan_result.dump.rssis2; + } delete[] frequency_scan_result.dump.freqs_khz; delete[] frequency_scan_result.dump.rssis; @@ -985,12 +1015,16 @@ void eventListenerForReport(void *arg, Event &e) frequency_scan_result.dump.freqs_khz = f; frequency_scan_result.dump.rssis = r; + frequency_scan_result.dump.rssis2 = r2; } frequency_scan_result.dump.freqs_khz[frequency_scan_result.dump.sz] = e.detected.freq * 1000; // convert to kHz frequency_scan_result.dump.rssis[frequency_scan_result.dump.sz] = max(e.detected.rssi, -999.0f); + if (radio2) + frequency_scan_result.dump.rssis2[frequency_scan_result.dump.sz] = + max(e.detected.rssi2, -999.0f); frequency_scan_result.dump.sz++; if (e.epoch != frequency_scan_result.last_epoch || @@ -1413,6 +1447,31 @@ void setup(void) wf_start = millis(); config = Config::init(); +#if defined(HAS_SDCARD) + SD.end(); + SDCardSPI.end(); // end SPI before other uses, eg radio2 over SPI +#endif + + pinMode(LED, OUTPUT); + pinMode(BUZZER_PIN, OUTPUT); + pinMode(REB_PIN, OUTPUT); + heltec_setup(); + + if (!initUARTs(config)) + { + Serial.println("Failed to initialize UARTs"); + } + + if (!initSPIs(config)) + { + Serial.println("Failed to initialize SPIs"); + } + + if (!initWires(config)) + { + Serial.println("Failed to initialize I2Cs"); + } + r.comms_initialized = Comms::initComms(config); if (r.comms_initialized) { @@ -1423,11 +1482,6 @@ void setup(void) Serial.println("Comms did not initialize"); } - pinMode(LED, OUTPUT); - pinMode(BUZZER_PIN, OUTPUT); - pinMode(REB_PIN, OUTPUT); - heltec_setup(); - #ifdef JOYSTICK_ENABLED calibrate_joy(); pinMode(JOY_BTN_PIN, INPUT_PULLUP); @@ -1653,20 +1707,27 @@ void setup(void) #endif - compass = new QMC5883LCompass(); - if (!compass->begin()) + if (wireDevices & QMC5883L || wire1Devices & QMC5883L) { - Serial.println("Failed to initialize Compass"); + compass = new QMC5883LCompass(wireDevices & QMC5883L ? Wire : Wire1); } - String err = compass->selfTest(); - if (err.startsWith("OK\n")) + if (compass) { - Serial.printf("Compass self-test passed: %s\n", err.c_str()); - } - else - { - Serial.printf("Compass self-sets failed: %s\n", err.c_str()); + if (!compass->begin()) + { + Serial.println("Failed to initialize Compass"); + } + + String err = compass->selfTest(); + if (err.startsWith("OK\n")) + { + Serial.printf("Compass self-test passed: %s\n", err.c_str()); + } + else + { + Serial.printf("Compass self-sets failed: %s\n", err.c_str()); + } } #ifdef UPTIME_CLOCK @@ -2677,6 +2738,14 @@ void doScan() int display_x = x / SCAN_RBW_FACTOR; freqX[(int)r.current_frequency] = display_x; setFrequency(curr_freq / 1000.0); + if (radio2 != NULL) + { + state = radio2->setFrequency(curr_freq / 1000.0); + if (state != RADIOLIB_ERR_NONE) + { + Serial.printf("Radio2: Failed to set freq: %d\n", state); + } + } LOG("Step:%d Freq: %f\n", x, r.current_frequency); // SpectralScan Method @@ -2708,6 +2777,8 @@ void doScan() #endif #ifdef METHOD_RSSI // Spectrum analyzer using getRSSI + float rssi2 = -999; + { LOG("METHOD RSSI"); @@ -2727,6 +2798,7 @@ void doScan() else g = &getRSSI; uint16_t max_rssi = 120; + // Scan if not in the ignore list if (ignoredFreq.find((int)r.current_frequency) == ignoredFreq.end()) { @@ -2738,6 +2810,11 @@ void doScan() { xRSSI[display_x] = (int)max_rssi; } + + for (int i = 0; radio2 != NULL && i < samples; i++) + { + rssi2 = max(rssi2, radio2->getRSSI()); + } } else { @@ -2773,6 +2850,7 @@ void doScan() Event event = r.detect(result, filtered_result, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, samples); event.time_ms = millis(); + event.detected.rssi2 = rssi2; size_t detected_at = event.detected.detected_at; if (max_rssi_x > detected_at)