diff --git a/boards/minewsemi_me25ls01.json b/boards/minewsemi_me25ls01.json new file mode 100644 index 00000000..4c943158 --- /dev/null +++ b/boards/minewsemi_me25ls01.json @@ -0,0 +1,59 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v7.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x8029"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"], + ["0x239A", "0x802A"] + ], + "usb_product": "me25ls01-BOOT", + "mcu": "nrf52840", + "variant": "minewsemi_me25ls01", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "7.3.0", + "sd_fwid": "0x0123" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "svd_path": "nrf52840.svd", + "openocd_target": "nrf52.cfg" + }, + "frameworks": ["arduino"], + "name": "Minewsemi ME25LS01", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "stlink", + "cmsis-dap", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://en.minewsemi.com/lora-module/lr1110-nrf52840-me25LS01", + "vendor": "MINEWSEMI" +} diff --git a/boards/seeed_sensecap_solar.json b/boards/seeed_sensecap_solar.json new file mode 100644 index 00000000..d6630d82 --- /dev/null +++ b/boards/seeed_sensecap_solar.json @@ -0,0 +1,60 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v7.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_Seeed_XIAO_nRF52840 -DNRF52840_XXAA -DSEEED_XIAO_NRF52840 ", + "f_cpu": "64000000L", + "hwids": [ + [ "0x2886", "0x0059" ] + ], + "mcu": "nrf52840", + "variant": "Seeed_XIAO_nRF52840", + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "7.3.0", + "sd_fwid": "0x0123" + }, + "bsp": { + "name": "adafruit" + }, + "bootloader": { + "settings_addr": "0xFF000" + }, + "usb_product": "XIAO nRF52840" + }, + "connectivity": [ + "bluetooth" + ], + "debug": { + "jlink_device": "nRF52840_xxAA", + "openocd_target": "nrf52.cfg", + "svd_path": "nrf52840.svd" + }, + "frameworks": [ + "arduino" + ], + "name": "Seeed Studio XIAO nRF52840", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "protocol": "nrfutil", + "speed": 115200, + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "cmsis-dap", + "sam-ba", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://wiki.seeedstudio.com/meshtastic_solar_node/", + "vendor": "Seeed Studio" +} \ No newline at end of file diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 23223622..6ddc19d6 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -319,13 +319,17 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); - } else { -#ifdef DISPLAY_CLASS - ui_task.soundBuzzer(UIEventType::contactMessage); -#endif } + #ifdef DISPLAY_CLASS - ui_task.newMsg(path_len, from.name, text, offline_queue_len); + // we only want to show text messages on display, not cli data + bool should_display = txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN; + if (should_display) { + ui_task.newMsg(path_len, from.name, text, offline_queue_len); + if (!_serial->isConnected()) { + ui_task.soundBuzzer(UIEventType::contactMessage); + } + } #endif } @@ -613,10 +617,10 @@ void MyMesh::begin(bool has_display) { _prefs.cr = constrain(_prefs.cr, 5, 8); _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER); -#ifdef BLE_PIN_CODE +#ifdef BLE_PIN_CODE // 123456 by default if (_prefs.ble_pin == 0) { #ifdef DISPLAY_CLASS - if (has_display) { + if (has_display && BLE_PIN_CODE == 123456) { StdRNG rng; _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session } else { diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 891a390e..247a9b3d 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -10,11 +10,11 @@ #define FIRMWARE_VER_CODE 6 #ifndef FIRMWARE_BUILD_DATE -#define FIRMWARE_BUILD_DATE "29 Jun 2025" +#define FIRMWARE_BUILD_DATE "2 Jul 2025" #endif #ifndef FIRMWARE_VERSION -#define FIRMWARE_VERSION "v1.7.1" +#define FIRMWARE_VERSION "v1.7.2" #endif #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 8b797991..71c9f24a 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "29 Jun 2025" + #define FIRMWARE_BUILD_DATE "2 Jul 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.7.1" + #define FIRMWARE_VERSION "v1.7.2" #endif #ifndef LORA_FREQ diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 07b68a20..5364ba44 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "29 Jun 2025" + #define FIRMWARE_BUILD_DATE "2 Jul 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.7.1" + #define FIRMWARE_VERSION "v1.7.2" #endif #ifndef LORA_FREQ diff --git a/platformio.ini b/platformio.ini index 90e7cfb0..d20508a8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,6 +29,20 @@ build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1 -D LORA_SF=11 -D ENABLE_PRIVATE_KEY_IMPORT=1 ; NOTE: comment these out for more secure firmware -D ENABLE_PRIVATE_KEY_EXPORT=1 + -D RADIOLIB_EXCLUDE_CC1101=1 + -D RADIOLIB_EXCLUDE_RF69=1 + -D RADIOLIB_EXCLUDE_SX1231=1 + -D RADIOLIB_EXCLUDE_SI443X=1 + -D RADIOLIB_EXCLUDE_RFM2X=1 + -D RADIOLIB_EXCLUDE_SX128X=1 + -D RADIOLIB_EXCLUDE_AFSK=1 + -D RADIOLIB_EXCLUDE_AX25=1 + -D RADIOLIB_EXCLUDE_HELLSCHREIBER=1 + -D RADIOLIB_EXCLUDE_MORSE=1 + -D RADIOLIB_EXCLUDE_APRS=1 + -D RADIOLIB_EXCLUDE_BELL=1 + -D RADIOLIB_EXCLUDE_RTTY=1 + -D RADIOLIB_EXCLUDE_SSTV=1 build_src_filter = +<*.cpp> + diff --git a/src/Mesh.cpp b/src/Mesh.cpp index ac949a94..e3101436 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -136,7 +136,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { int k = 0; uint8_t path_len = data[k++]; uint8_t* path = &data[k]; k += path_len; - uint8_t extra_type = data[k++]; + uint8_t extra_type = data[k++] & 0x0F; // upper 4 bits reserved for future use uint8_t* extra = &data[k]; uint8_t extra_len = len - k; // remainder of packet (may be padded with zeroes!) if (onPeerPathRecv(pkt, j, secret, path, path_len, extra_type, extra, extra_len)) { diff --git a/src/helpers/CustomLR1110.h b/src/helpers/CustomLR1110.h index 3451aac1..e82f48f5 100644 --- a/src/helpers/CustomLR1110.h +++ b/src/helpers/CustomLR1110.h @@ -9,6 +9,59 @@ class CustomLR1110 : public LR1110 { public: CustomLR1110(Module *mod) : LR1110(mod) { } + RadioLibTime_t getTimeOnAir(size_t len) override { + // calculate number of symbols + float N_symbol = 0; + if(this->codingRate <= RADIOLIB_LR11X0_LORA_CR_4_8_SHORT) { + // legacy coding rate - nice and simple + // get SF coefficients + float coeff1 = 0; + int16_t coeff2 = 0; + int16_t coeff3 = 0; + if(this->spreadingFactor < 7) { + // SF5, SF6 + coeff1 = 6.25; + coeff2 = 4*this->spreadingFactor; + coeff3 = 4*this->spreadingFactor; + } else if(this->spreadingFactor < 11) { + // SF7. SF8, SF9, SF10 + coeff1 = 4.25; + coeff2 = 4*this->spreadingFactor + 8; + coeff3 = 4*this->spreadingFactor; + } else { + // SF11, SF12 + coeff1 = 4.25; + coeff2 = 4*this->spreadingFactor + 8; + coeff3 = 4*(this->spreadingFactor - 2); + } + + // get CRC length + int16_t N_bitCRC = 16; + if(this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_DISABLED) { + N_bitCRC = 0; + } + + // get header length + int16_t N_symbolHeader = 20; + if(this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) { + N_symbolHeader = 0; + } + + // calculate number of LoRa preamble symbols - NO! Lora preamble is already in symbols + // uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); + + // calculate the number of symbols - nope + // N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); + // calculate the number of symbols - using only preamblelora because it's already in symbols + N_symbol = (float)preambleLengthLoRa + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); + } else { + // long interleaving - not needed for this modem + } + + // get time-on-air in us + return(((uint32_t(1) << this->spreadingFactor) / this->bandwidthKhz) * N_symbol * 1000.0f); +} + bool isReceiving() { uint16_t irq = getIrqStatus(); bool detected = ((irq & LR1110_IRQ_HEADER_VALID) || (irq & LR1110_IRQ_HAS_PREAMBLE)); diff --git a/src/helpers/CustomLR1110Wrapper.h b/src/helpers/CustomLR1110Wrapper.h index 7e2ffa2d..947bb51d 100644 --- a/src/helpers/CustomLR1110Wrapper.h +++ b/src/helpers/CustomLR1110Wrapper.h @@ -17,7 +17,7 @@ public: void onSendFinished() override { RadioLibWrapper::onSendFinished(); - _radio->setPreambleLength(8); // overcomes weird issues with small and big pkts + _radio->setPreambleLength(16); // overcomes weird issues with small and big pkts } float getLastRSSI() const override { return ((CustomLR1110 *)_radio)->getRSSI(); } diff --git a/src/helpers/HeltecV3Board.h b/src/helpers/HeltecV3Board.h index 57015a04..b71514cc 100644 --- a/src/helpers/HeltecV3Board.h +++ b/src/helpers/HeltecV3Board.h @@ -4,7 +4,7 @@ #include // LoRa radio module pins for Heltec V3 -// Also for Heltec Wireless Tracker +// Also for Heltec Wireless Tracker/Paper #define P_LORA_DIO_1 14 #define P_LORA_NSS 8 #define P_LORA_RESET RADIOLIB_NC @@ -14,7 +14,9 @@ #define P_LORA_MOSI 10 // built-ins -#define PIN_VBAT_READ 1 +#ifndef PIN_VBAT_READ // set in platformio.ini for boards like Heltec Wireless Paper (20) + #define PIN_VBAT_READ 1 +#endif #ifndef PIN_ADC_CTRL // set in platformio.ini for Heltec Wireless Tracker (2) #define PIN_ADC_CTRL 37 #endif diff --git a/src/helpers/MeshadventurerBoard.h b/src/helpers/MeshadventurerBoard.h new file mode 100644 index 00000000..65e11102 --- /dev/null +++ b/src/helpers/MeshadventurerBoard.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +// LoRa radio module pins for Meshadventurer +#define P_LORA_DIO_1 33 +#define P_LORA_NSS 18 +#define P_LORA_RESET 23 +#define P_LORA_BUSY 32 +#define P_LORA_SCLK 5 +#define P_LORA_MISO 19 +#define P_LORA_MOSI 27 + +#define PIN_VBAT_READ 35 + +#include "ESP32Board.h" + +#include + +class MeshadventurerBoard : public ESP32Board { + +public: + void begin() { + ESP32Board::begin(); + + esp_reset_reason_t reason = esp_reset_reason(); + if (reason == ESP_RST_DEEPSLEEP) { + long wakeup_source = esp_sleep_get_ext1_wakeup_status(); + if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep) + startup_reason = BD_STARTUP_RX_PACKET; + } + + rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS); + rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1); + } + } + + void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) { + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + + // Make sure the DIO1 and NSS GPIOs are held on required levels during deep sleep + rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); + + rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); + + if (pin_wake_btn < 0) { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet + } else { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn + } + + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); + } + + // Finally set ESP32 into sleep + esp_deep_sleep_start(); // CPU halts here and never returns! + } + + void powerOff() override { + // TODO: re-enable this when there is a definite wake-up source pin: + // enterDeepSleep(0); + } + + uint16_t getBattMilliVolts() override { + analogReadResolution(12); + + uint32_t raw = 0; + for (int i = 0; i < 4; i++) { + raw += analogReadMilliVolts(PIN_VBAT_READ); + } + raw = raw / 4; + + return (2 * raw); + } + + const char* getManufacturerName() const override { + return "Meshadventurer"; + } +}; diff --git a/src/helpers/nrf52/MinewsemiME25LS01Board.cpp b/src/helpers/nrf52/MinewsemiME25LS01Board.cpp new file mode 100644 index 00000000..c41a6bc0 --- /dev/null +++ b/src/helpers/nrf52/MinewsemiME25LS01Board.cpp @@ -0,0 +1,91 @@ +#include +#include "MinewsemiME25LS01Board.h" +#include + +#include + +void MinewsemiME25LS01Board::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + btn_prev_state = HIGH; + + pinMode(PIN_VBAT_READ, INPUT); + + sd_power_mode_set(NRF_POWER_MODE_LOWPWR); + +#ifdef BUTTON_PIN + pinMode(BUTTON_PIN, INPUT); + pinMode(LED_PIN, OUTPUT); +#endif + +#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) + Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); +#endif + + Wire.begin(); + +#ifdef P_LORA_TX_LED + pinMode(P_LORA_TX_LED, OUTPUT); + digitalWrite(P_LORA_TX_LED, LOW); +#endif + + delay(10); // give sx1262 some time to power up +} + +static BLEDfu bledfu; + +static void connect_callback(uint16_t conn_handle) { + (void)conn_handle; + MESH_DEBUG_PRINTLN("BLE client connected"); +} + +static void disconnect_callback(uint16_t conn_handle, uint8_t reason) { + (void)conn_handle; + (void)reason; + + MESH_DEBUG_PRINTLN("BLE client disconnected"); +} + + +bool MinewsemiME25LS01Board::startOTAUpdate(const char* id, char reply[]) { + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); + + Bluefruit.begin(1, 0); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + // Set the BLE device name + Bluefruit.setName("Minewsemi_OTA"); + + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); + + // Set up and start advertising + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); + + /* Start Advertising + - Enable auto advertising if disconnected + - Interval: fast mode = 20 ms, slow mode = 152.5 ms + - Timeout for fast mode is 30 seconds + - Start(timeout) with timeout = 0 will advertise forever (until connected) + + For recommended advertising interval + https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + + strcpy(reply, "OK - started"); + return true; +} \ No newline at end of file diff --git a/src/helpers/nrf52/MinewsemiME25LS01Board.h b/src/helpers/nrf52/MinewsemiME25LS01Board.h new file mode 100644 index 00000000..777606a6 --- /dev/null +++ b/src/helpers/nrf52/MinewsemiME25LS01Board.h @@ -0,0 +1,88 @@ +#pragma once + +#include +#include + +// LoRa and SPI pins + +#define P_LORA_DIO_1 (32 + 12) // P1.12 +#define P_LORA_NSS (32 + 13) // P1.13 +#define P_LORA_RESET (32 + 11) // P1.11 +#define P_LORA_BUSY (32 + 10) // P1.10 +#define P_LORA_SCLK (32 + 15) // P1.15 +#define P_LORA_MISO (0 + 29) // P0.29 +#define P_LORA_MOSI (0 + 2) // P0.2 + +#define LR11X0_DIO_AS_RF_SWITCH true +#define LR11X0_DIO3_TCXO_VOLTAGE 1.6 + +#define PIN_VBAT_READ BATTERY_PIN +#define ADC_MULTIPLIER (1.815f) // dependent on voltage divider resistors. TODO: more accurate battery tracking + + +class MinewsemiME25LS01Board : public mesh::MainBoard { +protected: + uint8_t startup_reason; + uint8_t btn_prev_state; + +public: + void begin(); + +#define BATTERY_SAMPLES 8 + + uint16_t getBattMilliVolts() override { + analogReadResolution(12); + + uint32_t raw = 0; + for (int i = 0; i < BATTERY_SAMPLES; i++) { + raw += analogRead(PIN_VBAT_READ); + } + raw = raw / BATTERY_SAMPLES; + return (ADC_MULTIPLIER * raw); + } + + uint8_t getStartupReason() const override { return startup_reason; } + + const char* getManufacturerName() const override { + return "Minewsemi"; + } + + void powerOff() override { + #ifdef HAS_GPS + digitalWrite(GPS_VRTC_EN, LOW); + digitalWrite(GPS_RESET, LOW); + digitalWrite(GPS_SLEEP_INT, LOW); + digitalWrite(GPS_RTC_INT, LOW); + pinMode(GPS_RESETB, OUTPUT); + digitalWrite(GPS_RESETB, LOW); + #endif + + #ifdef BUZZER_EN + digitalWrite(BUZZER_EN, LOW); + #endif + + #ifdef LED_PIN + digitalWrite(LED_PIN, LOW); + #endif + #ifdef BUTTON_PIN + nrf_gpio_cfg_sense_input(digitalPinToInterrupt(BUTTON_PIN), NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_HIGH); + #endif + sd_power_system_off(); + } + + #if defined(P_LORA_TX_LED) + void onBeforeTransmit() override { + digitalWrite(P_LORA_TX_LED, HIGH);// turn TX LED on + } + void onAfterTransmit() override { + digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off + } +#endif + + + void reboot() override { + NVIC_SystemReset(); + } + + bool startOTAUpdate(const char* id, char reply[]) override; +}; \ No newline at end of file diff --git a/src/helpers/nrf52/SerialBLEInterface.cpp b/src/helpers/nrf52/SerialBLEInterface.cpp index f43a3767..a8c11d97 100644 --- a/src/helpers/nrf52/SerialBLEInterface.cpp +++ b/src/helpers/nrf52/SerialBLEInterface.cpp @@ -1,6 +1,27 @@ #include "SerialBLEInterface.h" +static SerialBLEInterface* instance; + +void SerialBLEInterface::onConnect(uint16_t connection_handle) { + BLE_DEBUG_PRINTLN("SerialBLEInterface: connected"); + if(instance){ + instance->_isDeviceConnected = true; + // no need to stop advertising on connect, as the ble stack does this automatically + } +} + +void SerialBLEInterface::onDisconnect(uint16_t connection_handle, uint8_t reason) { + BLE_DEBUG_PRINTLN("SerialBLEInterface: disconnected reason=%d", reason); + if(instance){ + instance->_isDeviceConnected = false; + instance->startAdv(); + } +} + void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) { + + instance = this; + char charpin[20]; sprintf(charpin, "%d", pin_code); @@ -13,11 +34,31 @@ void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) { Bluefruit.Security.setMITM(true); Bluefruit.Security.setPIN(charpin); + Bluefruit.Periph.setConnectCallback(onConnect); + Bluefruit.Periph.setDisconnectCallback(onDisconnect); + // To be consistent OTA DFU should be added first if it exists //bledfu.begin(); + + // Configure and start the BLE Uart service + bleuart.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); + bleuart.begin(); + } void SerialBLEInterface::startAdv() { + + BLE_DEBUG_PRINTLN("SerialBLEInterface: starting advertising"); + + // clean restart if already advertising + if(Bluefruit.Advertising.isRunning()){ + BLE_DEBUG_PRINTLN("SerialBLEInterface: already advertising, stopping to allow clean restart"); + Bluefruit.Advertising.stop(); + } + + Bluefruit.Advertising.clearData(); // clear advertising data + Bluefruit.ScanResponse.clearData(); // clear scan response data + // Advertising packet Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); Bluefruit.Advertising.addTxPower(); @@ -38,10 +79,25 @@ void SerialBLEInterface::startAdv() { * For recommended advertising interval * https://developer.apple.com/library/content/qa/qa1931/_index.html */ - Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.restartOnDisconnect(false); // don't restart automatically as we handle it in onDisconnect Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode - Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + +} + +void SerialBLEInterface::stopAdv() { + + BLE_DEBUG_PRINTLN("SerialBLEInterface: stopping advertising"); + + // we only want to stop advertising if it's running, otherwise an invalid state error is logged by ble stack + if(!Bluefruit.Advertising.isRunning()){ + return; + } + + // stop advertising + Bluefruit.Advertising.stop(); + } // ---------- public methods @@ -52,25 +108,14 @@ void SerialBLEInterface::enable() { _isEnabled = true; clearBuffers(); - // Configure and start the BLE Uart service - bleuart.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); - bleuart.begin(); - // Start advertising startAdv(); - - checkAdvRestart = false; } void SerialBLEInterface::disable() { _isEnabled = false; - BLE_DEBUG_PRINTLN("SerialBLEInterface::disable"); - - Bluefruit.Advertising.stop(); - - oldDeviceConnected = deviceConnected = false; - checkAdvRestart = false; + stopAdv(); } size_t SerialBLEInterface::writeFrame(const uint8_t src[], size_t len) { @@ -79,7 +124,7 @@ size_t SerialBLEInterface::writeFrame(const uint8_t src[], size_t len) { return 0; } - if (deviceConnected && len > 0) { + if (_isDeviceConnected && len > 0) { if (send_queue_len >= FRAME_QUEUE_SIZE) { BLE_DEBUG_PRINTLN("writeFrame(), send_queue is full!"); return 0; @@ -115,44 +160,14 @@ size_t SerialBLEInterface::checkRecvFrame(uint8_t dest[]) { } else { int len = bleuart.available(); if (len > 0) { - deviceConnected = true; // should probably use the callback to monitor cx bleuart.readBytes(dest, len); BLE_DEBUG_PRINTLN("readBytes: sz=%d, hdr=%d", len, (uint32_t) dest[0]); return len; } } - - if (Bluefruit.connected() == 0) deviceConnected = false; - - if (deviceConnected != oldDeviceConnected) { - if (!deviceConnected) { // disconnecting - clearBuffers(); - - BLE_DEBUG_PRINTLN("SerialBLEInterface -> disconnecting..."); - delay(500); // give the bluetooth stack the chance to get things ready - - checkAdvRestart = true; - } else { - BLE_DEBUG_PRINTLN("SerialBLEInterface -> stopping advertising"); - BLE_DEBUG_PRINTLN("SerialBLEInterface -> connecting..."); - // connecting - // do stuff here on connecting - Bluefruit.Advertising.stop(); - checkAdvRestart = false; - } - oldDeviceConnected = deviceConnected; - } - - if (checkAdvRestart) { - if (Bluefruit.connected() == 0) { - BLE_DEBUG_PRINTLN("SerialBLEInterface -> re-starting advertising"); - startAdv(); - } - checkAdvRestart = false; - } return 0; } bool SerialBLEInterface::isConnected() const { - return deviceConnected; //pServer != NULL && pServer->getConnectedCount() > 0; + return _isDeviceConnected; } diff --git a/src/helpers/nrf52/SerialBLEInterface.h b/src/helpers/nrf52/SerialBLEInterface.h index d5555f56..12a4f46a 100644 --- a/src/helpers/nrf52/SerialBLEInterface.h +++ b/src/helpers/nrf52/SerialBLEInterface.h @@ -5,10 +5,8 @@ class SerialBLEInterface : public BaseSerialInterface { BLEUart bleuart; - bool deviceConnected; - bool oldDeviceConnected; - bool checkAdvRestart; bool _isEnabled; + bool _isDeviceConnected; unsigned long _last_write; struct Frame { @@ -21,18 +19,19 @@ class SerialBLEInterface : public BaseSerialInterface { Frame send_queue[FRAME_QUEUE_SIZE]; void clearBuffers() { send_queue_len = 0; } - void startAdv(); + static void onConnect(uint16_t connection_handle); + static void onDisconnect(uint16_t connection_handle, uint8_t reason); public: SerialBLEInterface() { - deviceConnected = false; - oldDeviceConnected = false; - checkAdvRestart = false; _isEnabled = false; + _isDeviceConnected = false; _last_write = 0; send_queue_len = 0; } + void startAdv(); + void stopAdv(); void begin(const char* device_name, uint32_t pin_code); // BaseSerialInterface methods diff --git a/src/helpers/rp2040/XiaoRP2040Board.cpp b/src/helpers/rp2040/XiaoRP2040Board.cpp new file mode 100644 index 00000000..bb439706 --- /dev/null +++ b/src/helpers/rp2040/XiaoRP2040Board.cpp @@ -0,0 +1,30 @@ +#include "XiaoRP2040Board.h" + +#include +#include + +void XiaoRP2040Board::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + +#ifdef P_LORA_TX_LED + pinMode(P_LORA_TX_LED, OUTPUT); +#endif + +#ifdef PIN_VBAT_READ + pinMode(PIN_VBAT_READ, INPUT); +#endif + +#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) + Wire.setSDA(PIN_BOARD_SDA); + Wire.setSCL(PIN_BOARD_SCL); +#endif + + Wire.begin(); + + delay(10); // give sx1262 some time to power up +} + +bool XiaoRP2040Board::startOTAUpdate(const char *id, char reply[]) { + return false; +} diff --git a/src/helpers/rp2040/XiaoRP2040Board.h b/src/helpers/rp2040/XiaoRP2040Board.h new file mode 100644 index 00000000..c9353906 --- /dev/null +++ b/src/helpers/rp2040/XiaoRP2040Board.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +// LoRa radio module pins for the Xiao RP2040 +// https://wiki.seeedstudio.com/XIAO-RP2040/ + +#define P_LORA_DIO_1 27 // D1 +#define P_LORA_NSS 6 // D4 +#define P_LORA_RESET 28 // D2 +#define P_LORA_BUSY 29 // D3 +#define P_LORA_TX_LED 17 + +#define SX126X_RXEN 7 // D5 +#define SX126X_TXEN -1 + +#define SX126X_DIO2_AS_RF_SWITCH true +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +/* + * This board has no built-in way to read battery voltage. + * Nevertheless it's very easy to make it work, you only require two 1% resistors. + * If your using the WIO SX1262 Addon for xaio, make sure you dont connect D0! + * + * BAT+ -----+ + * | + * VSYS --+ -/\/\/\/\- --+ + * 200k | + * +-- D0 + * | + * GND --+ -/\/\/\/\- --+ + * | 100k + * BAT- -----+ + */ +#define PIN_VBAT_READ 26 // D0 +#define BATTERY_SAMPLES 8 +#define ADC_MULTIPLIER (3.0f * 3.3f * 1000) + +class XiaoRP2040Board : public mesh::MainBoard { +protected: + uint8_t startup_reason; + +public: + void begin(); + uint8_t getStartupReason() const override { return startup_reason; } + +#ifdef P_LORA_TX_LED + void onBeforeTransmit() override { digitalWrite(P_LORA_TX_LED, HIGH); } + void onAfterTransmit() override { digitalWrite(P_LORA_TX_LED, LOW); } +#endif + + + uint16_t getBattMilliVolts() override { +#if defined(PIN_VBAT_READ) && defined(ADC_MULTIPLIER) + analogReadResolution(12); + + uint32_t raw = 0; + for (int i = 0; i < BATTERY_SAMPLES; i++) { + raw += analogRead(PIN_VBAT_READ); + } + raw = raw / BATTERY_SAMPLES; + + return (ADC_MULTIPLIER * raw) / 4096; +#else + return 0; +#endif + } + + const char *getManufacturerName() const override { return "Xiao RP2040"; } + + void reboot() override { rp2040.reboot(); } + + bool startOTAUpdate(const char *id, char reply[]) override; +}; diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index b672cdd4..a424c46b 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -24,6 +24,14 @@ static Adafruit_BME280 BME280; static Adafruit_BMP280 BMP280; #endif +#if ENV_INCLUDE_SHTC3 +#include +static Adafruit_SHTC3 SHTC3; +#endif + +#if ENV_INCLUDE_LPS22HB +#include +#endif #if ENV_INCLUDE_INA3221 #define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address @@ -76,28 +84,48 @@ bool EnvironmentSensorManager::begin() { } #endif + #if ENV_INCLUDE_SHTC3 + if (SHTC3.begin()) { + MESH_DEBUG_PRINTLN("Found sensor: SHTC3"); + SHTC3_initialized = true; + } else { + SHTC3_initialized = false; + MESH_DEBUG_PRINTLN("SHTC3 was not found at I2C address %02X", 0x70); + } + #endif + + #if ENV_INCLUDE_LPS22HB + if (BARO.begin()) { + MESH_DEBUG_PRINTLN("Found sensor: LPS22HB"); + LPS22HB_initialized = true; + } else { + LPS22HB_initialized = false; + MESH_DEBUG_PRINTLN("LPS22HB was not found at I2C address %02X", 0x5C); + } + #endif + #if ENV_INCLUDE_INA3221 if (INA3221.begin(TELEM_INA3221_ADDRESS, &Wire)) { - MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); - MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); + MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); + MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); - for(int i = 0; i < 3; i++) { - INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE); - } - INA3221_initialized = true; + for(int i = 0; i < 3; i++) { + INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE); + } + INA3221_initialized = true; } else { - INA3221_initialized = false; - MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); + INA3221_initialized = false; + MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); } #endif #if ENV_INCLUDE_INA219 if (INA219.begin(&Wire)) { - MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); - INA219_initialized = true; + MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); + INA219_initialized = true; } else { - INA219_initialized = false; - MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); + INA219_initialized = false; + MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); } #endif @@ -139,6 +167,23 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen } #endif + #if ENV_INCLUDE_SHTC3 + if (SHTC3_initialized) { + sensors_event_t humidity, temp; + SHTC3.getEvent(&humidity, &temp); + + telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); + } + #endif + + #if ENV_INCLUDE_LPS22HB + if (LPS22HB_initialized) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, BARO.readTemperature()); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BARO.readPressure()); + } + #endif + #if ENV_INCLUDE_INA3221 if (INA3221_initialized) { for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) { @@ -157,10 +202,10 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen #if ENV_INCLUDE_INA219 if (INA219_initialized) { - telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V()); - telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000); - telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000); - next_available_channel++; + telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V()); + telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000); + telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000); + next_available_channel++; } #endif diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 76bffc48..f7804431 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -13,6 +13,8 @@ protected: bool BMP280_initialized = false; bool INA3221_initialized = false; bool INA219_initialized = false; + bool SHTC3_initialized = false; + bool LPS22HB_initialized = false; bool gps_detected = false; bool gps_active = false; diff --git a/src/helpers/ui/E213Display.cpp b/src/helpers/ui/E213Display.cpp new file mode 100644 index 00000000..92bf37fb --- /dev/null +++ b/src/helpers/ui/E213Display.cpp @@ -0,0 +1,116 @@ +#include "E213Display.h" + +#include "../../MeshCore.h" + +bool E213Display::begin() { + if (_init) return true; + + powerOn(); + display.begin(); + + // Set to landscape mode rotated 180 degrees + display.setRotation(3); + + _init = true; + _isOn = true; + + clear(); + display.fastmodeOn(); // Enable fast mode for quicker (partial) updates + + return true; +} + +void E213Display::powerOn() { +#ifdef PIN_VEXT_EN + pinMode(PIN_VEXT_EN, OUTPUT); + digitalWrite(PIN_VEXT_EN, LOW); // Active low + delay(50); // Allow power to stabilize +#endif +} + +void E213Display::powerOff() { +#ifdef PIN_VEXT_EN + digitalWrite(PIN_VEXT_EN, HIGH); // Turn off power +#endif +} + +void E213Display::turnOn() { + if (!_init) begin(); + powerOn(); + _isOn = true; +} + +void E213Display::turnOff() { + powerOff(); + _isOn = false; +} + +void E213Display::clear() { + display.clear(); +} + +void E213Display::startFrame(Color bkg) { + // Fill screen with white first to ensure clean background + display.fillRect(0, 0, width(), height(), WHITE); + if (bkg == LIGHT) { + // Fill with black if light background requested (inverted for e-ink) + display.fillRect(0, 0, width(), height(), BLACK); + } +} + +void E213Display::setTextSize(int sz) { + // The library handles text size internally + display.setTextSize(sz); +} + +void E213Display::setColor(Color c) { + // implemented in individual display methods +} + +void E213Display::setCursor(int x, int y) { + display.setCursor(x, y); +} + +void E213Display::print(const char *str) { + display.print(str); +} + +void E213Display::fillRect(int x, int y, int w, int h) { + display.fillRect(x, y, w, h, BLACK); +} + +void E213Display::drawRect(int x, int y, int w, int h) { + display.drawRect(x, y, w, h, BLACK); +} + +void E213Display::drawXbm(int x, int y, const uint8_t *bits, int w, int h) { + // Width in bytes for bitmap processing + uint16_t widthInBytes = (w + 7) / 8; + + // Process the bitmap row by row + for (int by = 0; by < h; by++) { + // Scan across the row bit by bit + for (int bx = 0; bx < w; bx++) { + // Get the current bit using MSB ordering (like GxEPDDisplay) + uint16_t byteOffset = (by * widthInBytes) + (bx / 8); + uint8_t bitMask = 0x80 >> (bx & 7); + bool bitSet = bits[byteOffset] & bitMask; + + // If the bit is set, draw the pixel + if (bitSet) { + display.drawPixel(x + bx, y + by, BLACK); + } + } + } +} + +uint16_t E213Display::getTextWidth(const char *str) { + int16_t x1, y1; + uint16_t w, h; + display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h); + return w; +} + +void E213Display::endFrame() { + display.update(); +} diff --git a/src/helpers/ui/E213Display.h b/src/helpers/ui/E213Display.h new file mode 100644 index 00000000..330a2b6d --- /dev/null +++ b/src/helpers/ui/E213Display.h @@ -0,0 +1,37 @@ +#pragma once + +#include "DisplayDriver.h" + +#include +#include +#include + +// Display driver for E213 e-ink display +class E213Display : public DisplayDriver { + EInkDisplay_VisionMasterE213 display; + bool _init = false; + bool _isOn = false; + +public: + E213Display() : DisplayDriver(250, 122) {} + + bool begin(); + bool isOn() override { return _isOn; } + void turnOn() override; + void turnOff() override; + void clear() override; + void startFrame(Color bkg = DARK) override; + void setTextSize(int sz) override; + void setColor(Color c) override; + void setCursor(int x, int y) override; + void print(const char *str) override; + void fillRect(int x, int y, int w, int h) override; + void drawRect(int x, int y, int w, int h) override; + void drawXbm(int x, int y, const uint8_t *bits, int w, int h) override; + uint16_t getTextWidth(const char *str) override; + void endFrame() override; + +private: + void powerOn(); + void powerOff(); +}; \ No newline at end of file diff --git a/variants/heltec_tracker/target.cpp b/variants/heltec_tracker/target.cpp index 042c7c0d..f41702c5 100644 --- a/variants/heltec_tracker/target.cpp +++ b/variants/heltec_tracker/target.cpp @@ -23,43 +23,16 @@ HWTSensorManager sensors = HWTSensorManager(nmea); DISPLAY_CLASS display(&board.periph_power); // peripheral power pin is shared #endif -#ifndef LORA_CR - #define LORA_CR 5 -#endif - bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire); -#ifdef SX126X_DIO3_TCXO_VOLTAGE - float tcxo = SX126X_DIO3_TCXO_VOLTAGE; -#else - float tcxo = 1.6f; -#endif - #if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); -#endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - - radio.setCRC(1); - -#ifdef SX126X_CURRENT_LIMIT - radio.setCurrentLimit(SX126X_CURRENT_LIMIT); -#endif -#ifdef SX126X_DIO2_AS_RF_SWITCH - radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); -#endif -#ifdef SX126X_RX_BOOSTED_GAIN - radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); + return radio.std_init(&spi); +#else + return radio.std_init(); #endif - return true; // success } uint32_t radio_get_rng_seed() { diff --git a/variants/heltec_v2/platformio.ini b/variants/heltec_v2/platformio.ini index 562b309d..43bc43ad 100644 --- a/variants/heltec_v2/platformio.ini +++ b/variants/heltec_v2/platformio.ini @@ -96,7 +96,7 @@ build_flags = -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 - -D BLE_PIN_CODE=0 + -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 ; -D MESH_PACKET_LOGGING=1 diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index 17a0899a..a4b6bf6f 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -23,9 +23,9 @@ build_flags = -D ENV_INCLUDE_INA3221=1 -D ENV_INCLUDE_INA219=1 -D ENV_INCLUDE_GPS=1 - -D PIN_GPS_RX=45 - -D PIN_GPS_TX=46 - -D PIN_GPS_EN=-1 + -D PIN_GPS_RX=47 + -D PIN_GPS_TX=48 + -D PIN_GPS_EN=26 build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_v3> + @@ -114,7 +114,7 @@ build_flags = -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=SSD1306Display - -D BLE_PIN_CODE=0 ; dynamic, random PIN + -D BLE_PIN_CODE=123456 ; dynamic, random PIN -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 ; -D MESH_PACKET_LOGGING=1 diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini new file mode 100644 index 00000000..513ba4b9 --- /dev/null +++ b/variants/heltec_wireless_paper/platformio.ini @@ -0,0 +1,84 @@ +[Heltec_Wireless_Paper_base] +extends = esp32_base +board = esp32-s3-devkitc-1 +build_flags = + ${esp32_base.build_flags} + -I variants/heltec_wireless_paper + -D HELTEC_WIRELESS_PAPER + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D P_LORA_TX_LED=18 + ; -D PIN_BOARD_SDA=17 + ; -D PIN_BOARD_SCL=18 + -D PIN_USER_BTN=0 + -D PIN_VEXT_EN=45 + -D PIN_VBAT_READ=20 + -D PIN_ADC_CTRL=19 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D DISP_CS=4 + -D DISP_BUSY=7 + -D DISP_DC=5 + -D DISP_RST=6 + -D DISP_SCLK=3 + -D DISP_MOSI=2 + -D ARDUINO_heltec_wifi_lora_32_V3 + -D WIRELESS_PAPER +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/heltec_wireless_paper> +lib_deps = + ${esp32_base.lib_deps} + todd-herbert/heltec-eink-modules @ 4.5.0 + +[env:Heltec_Wireless_Paper_companion_radio_ble] +extends = Heltec_Wireless_Paper_base +build_flags = + ${Heltec_Wireless_Paper_base.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D DISPLAY_CLASS=E213Display + -D BLE_PIN_CODE=123456 ; dynamic, random PIN + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} + + + + + +<../examples/companion_radio> +lib_deps = + ${Heltec_Wireless_Paper_base.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Heltec_Wireless_Paper_repeater] +extends = Heltec_Wireless_Paper_base +build_flags = + ${Heltec_Wireless_Paper_base.build_flags} + -D DISPLAY_CLASS=E213Display + -D ADVERT_NAME='"Heltec WP Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 +build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} + + + +<../examples/simple_repeater> +lib_deps = + ${Heltec_Wireless_Paper_base.lib_deps} + ${esp32_ota.lib_deps} + +[env:Heltec_Wireless_Paper_room_server] +extends = Heltec_Wireless_Paper_base +build_flags = + ${Heltec_Wireless_Paper_base.build_flags} + -D DISPLAY_CLASS=E213Display + -D ADVERT_NAME='"Heltec WP Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} + + + +<../examples/simple_room_server> +lib_deps = + ${Heltec_Wireless_Paper_base.lib_deps} + ${esp32_ota.lib_deps} \ No newline at end of file diff --git a/variants/heltec_wireless_paper/target.cpp b/variants/heltec_wireless_paper/target.cpp new file mode 100644 index 00000000..65eaab04 --- /dev/null +++ b/variants/heltec_wireless_paper/target.cpp @@ -0,0 +1,45 @@ +#include "target.h" + +#include + +HeltecV3Board board; + +static SPIClass spi; +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); + +SensorManager sensors; + +#ifdef DISPLAY_CLASS +DISPLAY_CLASS display; +#endif + +bool radio_init() { + fallback_clock.begin(); + rtc_clock.begin(Wire); + return radio.std_init(&spi); +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} \ No newline at end of file diff --git a/variants/heltec_wireless_paper/target.h b/variants/heltec_wireless_paper/target.h new file mode 100644 index 00000000..7d901c01 --- /dev/null +++ b/variants/heltec_wireless_paper/target.h @@ -0,0 +1,27 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS +#include +#endif + +extern HeltecV3Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager sensors; + +#ifdef DISPLAY_CLASS +extern DISPLAY_CLASS display; +#endif + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/lilygo_t3s3/target.cpp b/variants/lilygo_t3s3/target.cpp index 7fa45e54..b7c4542c 100644 --- a/variants/lilygo_t3s3/target.cpp +++ b/variants/lilygo_t3s3/target.cpp @@ -3,13 +3,8 @@ ESP32Board board; -#if defined(P_LORA_SCLK) - static SPIClass spi; - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); -#else - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); -#endif - +static SPIClass spi; +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); WRAPPER_CLASS radio_driver(radio, board); ESP32RTCClock fallback_clock; @@ -28,35 +23,7 @@ bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire); -#ifdef SX126X_DIO3_TCXO_VOLTAGE - float tcxo = SX126X_DIO3_TCXO_VOLTAGE; -#else - float tcxo = 1.6f; -#endif - -#if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); -#endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - - radio.setCRC(1); - -#ifdef SX126X_CURRENT_LIMIT - radio.setCurrentLimit(SX126X_CURRENT_LIMIT); -#endif -#ifdef SX126X_DIO2_AS_RF_SWITCH - radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); -#endif -#ifdef SX126X_RX_BOOSTED_GAIN - radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); -#endif - - return true; // success + return radio.std_init(&spi); } uint32_t radio_get_rng_seed() { diff --git a/variants/lilygo_tbeam_SX1262/platformio.ini b/variants/lilygo_tbeam_SX1262/platformio.ini index 8bf2c5ab..eac899f0 100644 --- a/variants/lilygo_tbeam_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_SX1262/platformio.ini @@ -69,4 +69,21 @@ build_src_filter = ${LilyGo_TBeam_SX1262.build_src_filter} +<../examples/simple_repeater> lib_deps = ${LilyGo_TBeam_SX1262.lib_deps} - ${esp32_ota.lib_deps} \ No newline at end of file + ${esp32_ota.lib_deps} + +[env:Tbeam_SX1262_room_server] +extends = LilyGo_TBeam_SX1262 +build_flags = + ${LilyGo_TBeam_SX1262.build_flags} + -D ADVERT_NAME='"Tbeam SX1262 Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${LilyGo_TBeam_SX1262.build_src_filter} + +<../examples/simple_room_server> +lib_deps = + ${LilyGo_TBeam_SX1262.lib_deps} + ${esp32_ota.lib_deps} diff --git a/variants/meshadventurer/platformio.ini b/variants/meshadventurer/platformio.ini new file mode 100644 index 00000000..f8995e18 --- /dev/null +++ b/variants/meshadventurer/platformio.ini @@ -0,0 +1,234 @@ +[Meshadventurer] +extends = esp32_base +board = esp32doit-devkit-v1 +board_build.partitions = min_spiffs.csv ; get around 4mb flash limit +build_flags = + ${esp32_base.build_flags} + -I variants/meshadventurer + -D MESHADVENTURER + -D P_LORA_TX_LED=2 + -D PIN_VBAT_READ=35 + -D PIN_USER_BTN_ANA=39 + -D P_LORA_DIO_1=33 + -D P_LORA_NSS=18 + -D P_LORA_RESET=23 + -D P_LORA_BUSY=32 + -D P_LORA_SCLK=5 + -D P_LORA_MOSI=27 + -D P_LORA_MISO=19 + -D SX126X_TXEN=13 + -D SX126X_RXEN=14 + -D PIN_BOARD_SDA=21 + -D PIN_BOARD_SCL=22 + -D SX126X_DIO2_AS_RF_SWITCH=false + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_RX_BOOSTED_GAIN=1 + -D PIN_GPS_RX=12 + -D PIN_GPS_TX=15 + -D DISPLAY_CLASS=SSD1306Display +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/meshadventurer> +lib_deps = + ${esp32_base.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 + adafruit/Adafruit SSD1306 @ ^2.5.13 + +[env:Meshadventurer_sx1262_repeater] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_repeater> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} + +[env:Meshadventurer_sx1268_repeater] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_repeater> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} + +[env:Meshadventurer_sx1262_companion_radio_usb] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1262_companion_radio_ble] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1262_terminal_chat] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> + + +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1262_room_server] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_room_server> + + +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} + +[env:Meshadventurer_sx1268_companion_radio_usb] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1268_companion_radio_ble] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1268_terminal_chat] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> + + +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1268_room_server] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_room_server> + + +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} \ No newline at end of file diff --git a/variants/meshadventurer/target.cpp b/variants/meshadventurer/target.cpp new file mode 100644 index 00000000..a1d6dcad --- /dev/null +++ b/variants/meshadventurer/target.cpp @@ -0,0 +1,119 @@ +#include +#include "target.h" + +#include + +MeshadventurerBoard board; + +static SPIClass spi; +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +MASensorManager sensors = MASensorManager(nmea); + +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +bool radio_init() { + fallback_clock.begin(); + rtc_clock.begin(Wire); + +#if defined(P_LORA_SCLK) + return radio.std_init(&spi); +#else + return radio.std_init(); +#endif +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} + +void MASensorManager::start_gps() { + if(!gps_active) { + MESH_DEBUG_PRINTLN("starting GPS"); + gps_active = true; + } +} + +void MASensorManager::stop_gps() { + if(gps_active) { + MESH_DEBUG_PRINTLN("stopping GPS"); + gps_active = false; + } +} + +bool MASensorManager::begin() { + Serial1.setPins(PIN_GPS_RX, PIN_GPS_TX); + Serial1.begin(9600); + delay(500); + return true; +} + +bool MASensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + if(requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); + } + return true; +} + +void MASensorManager::loop() { + static long next_gps_update = 0; + _location->loop(); + if(millis() > next_gps_update && gps_active) { + if(_location->isValid()) { + node_lat = ((double)_location->getLatitude()) / 1000000.; + node_lon = ((double)_location->getLongitude()) / 1000000.; + node_altitude = ((double)_location->getAltitude()) / 1000.0; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + next_gps_update = millis() + 1000; + } +} + +int MASensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) + +const char* MASensorManager::getSettingName(int i) const { + return i == 0 ? "gps" : NULL; +} +const char* MASensorManager::getSettingValue(int i) const { + if(i == 0) { + return gps_active ? "1" : "0"; + } + return NULL; +} +bool MASensorManager::setSettingValue(const char* name, const char* value) { + if(strcmp(name, "gps") == 0) { + if(strcmp(value, "0") == 0) { + stop_gps(); + } else { + start_gps(); + } + return true; + } + return false; // not supported +} diff --git a/variants/meshadventurer/target.h b/variants/meshadventurer/target.h new file mode 100644 index 00000000..0e0235ba --- /dev/null +++ b/variants/meshadventurer/target.h @@ -0,0 +1,46 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include +#endif + +class MASensorManager : public SensorManager { + bool gps_active = false; + LocationProvider * _location; + + void start_gps(); + void stop_gps(); +public: + MASensorManager(LocationProvider &location): _location(&location) { } + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + void loop() override; + int getNumSettings() const override; + const char* getSettingName(int i) const override; + const char* getSettingValue(int i) const override; + bool setSettingValue(const char* name, const char* value) override; +}; + +extern MeshadventurerBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern MASensorManager sensors; + +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/meshadventurer/variant.h b/variants/meshadventurer/variant.h new file mode 100644 index 00000000..356a3e17 --- /dev/null +++ b/variants/meshadventurer/variant.h @@ -0,0 +1,44 @@ +// For OLED LCD +#define I2C_SDA 21 +#define I2C_SCL 22 + +// For GPS, 'undef's not needed +#define GPS_TX_PIN 15 +#define GPS_RX_PIN 12 +#define PIN_GPS_EN 4 +#define GPS_POWER_TOGGLE // Moved definition from platformio.ini to here + +#define BUTTON_PIN 39 // The middle button GPIO on the T-Beam +#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO35_CHANNEL +#define ADC_MULTIPLIER 2 +#define EXT_PWR_DETECT 4 // Pin to detect connected external power source for LILYGO® TTGO T-Energy T18 and other DIY boards +#define EXT_NOTIFY_OUT 12 // Overridden default pin to use for Ext Notify Module (#975). +#define LED_PIN 2 // add status LED (compatible with core-pcb and DIY targets) + +// Radio +#define USE_SX1262 // E22-900M30S uses SX1262 +#define USE_SX1268 // E22-400M30S uses SX1268 +#define SX126X_MAX_POWER 22 // Outputting 22dBm from SX1262 results in ~30dBm E22-900M30S output (module only uses last stage of the YP2233W PA) +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // E22 series TCXO reference voltage is 1.8V + +#define SX126X_CS 18 // EBYTE module's NSS pin +#define SX126X_SCK 5 // EBYTE module's SCK pin +#define SX126X_MOSI 27 // EBYTE module's MOSI pin +#define SX126X_MISO 19 // EBYTE module's MISO pin +#define SX126X_RESET 23 // EBYTE module's NRST pin +#define SX126X_BUSY 32 // EBYTE module's BUSY pin +#define SX126X_DIO1 33 // EBYTE module's DIO1 pin + +// The E22's TXEN pin is connected to MCU pin, E22's RXEN pin is connected to MCU pin (allows for ramping up PA before transmission +// Don't define DIO2_AS_RF_SWITCH because we only use DIO2 or an MCU pin mutually exclusively to connect to E22's TXEN (to prevent +// a short if they are both connected at the same time and there's a slight non-neglibible delay and/or voltage difference between +// DIO2 and TXEN). +#define SX126X_TXEN 13 // Schematic connects EBYTE module's TXEN pin to MCU +#define SX126X_RXEN 14 // Schematic connects EBYTE module's RXEN pin to MCU + +#define LORA_CS SX126X_CS // Compatibility with variant file configuration structure +#define LORA_SCK SX126X_SCK // Compatibility with variant file configuration structure +#define LORA_MOSI SX126X_MOSI // Compatibility with variant file configuration structure +#define LORA_MISO SX126X_MISO // Compatibility with variant file configuration structure +#define LORA_DIO1 SX126X_DIO1 // Compatibility with variant file configuration structure diff --git a/variants/minewsemi_me25ls01/NullDisplayDriver.h b/variants/minewsemi_me25ls01/NullDisplayDriver.h new file mode 100644 index 00000000..38bf93f1 --- /dev/null +++ b/variants/minewsemi_me25ls01/NullDisplayDriver.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +class NullDisplayDriver : public DisplayDriver { +public: + NullDisplayDriver() : DisplayDriver(128, 64) { } + bool begin() { return false; } // not present + + bool isOn() override { return false; } + void turnOn() override { } + void turnOff() override { } + void clear() override { } + void startFrame(Color bkg = DARK) override { } + void setTextSize(int sz) override { } + void setColor(Color c) override { } + void setCursor(int x, int y) override { } + void print(const char* str) override { } + void fillRect(int x, int y, int w, int h) override { } + void drawRect(int x, int y, int w, int h) override { } + void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override { } + uint16_t getTextWidth(const char* str) override { return 0; } + void endFrame() { } +}; diff --git a/variants/minewsemi_me25ls01/platformio.ini b/variants/minewsemi_me25ls01/platformio.ini new file mode 100644 index 00000000..302e695f --- /dev/null +++ b/variants/minewsemi_me25ls01/platformio.ini @@ -0,0 +1,165 @@ +; ----------------- NRF52 me25ls01--------------------- +[nrf52840_me25ls01] +extends = nrf52_base +platform_packages = framework-arduinoadafruitnrf52 +build_flags = ${nrf52_base.build_flags} + -I src/helpers/nrf52 + -I lib/nrf52/s140_nrf52_7.3.0_API/include + -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52 +lib_ignore = + BluetoothOTA + lib5b4 +lib_deps = + ${nrf52_base.lib_deps} + rweather/Crypto @ ^0.4.0 + +[me25ls01] +extends = nrf52840_me25ls01 +board = minewsemi_me25ls01 +board_build.ldscript = boards/nrf52840_s140_v7.ld +build_flags = ${nrf52840_me25ls01.build_flags} + -I variants/minewsemi_me25ls01 + -D me25ls01 + -D PIN_USER_BTN=27 + -D USER_BTN_PRESSED=HIGH + -D PIN_STATUS_LED=39 + -D P_LORA_TX_LED=22 + -D RADIO_CLASS=CustomLR1110 + -D WRAPPER_CLASS=CustomLR1110Wrapper + -D LORA_TX_POWER=22 + -D ENV_INCLUDE_GPS=0 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 +build_src_filter = ${nrf52840_me25ls01.build_src_filter} + + + + + +<../variants/minewsemi_me25ls01> + + +debug_tool = jlink +upload_protocol = nrfutil +lib_deps = ${nrf52840_me25ls01.lib_deps} + densaugeo/base64 @ ~1.4.0 + stevemarple/MicroNMEA @ ^2.0.6 + end2endzone/NonBlockingRTTTL@^1.3.0 + adafruit/Adafruit SSD1306 @ ^2.5.13 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 + +[env:Minewsemi_me25ls01_companion_radio_ble] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D DISPLAY_CLASS=NullDisplayDriver + ;-D PIN_BUZZER=25 + ;-D PIN_BUZZER_EN=37 +build_src_filter = ${me25ls01.build_src_filter} + + + +<../examples/companion_radio/*.cpp> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + + +[env:Minewsemi_me25ls01_repeater] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D ADVERT_NAME='"ME25LS01 Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${me25ls01.build_src_filter} + +<../examples/simple_repeater> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + + + +[env:Minewsemi_me25ls01_room_server] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D ADVERT_NAME='"ME25LS01 Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' + -D MAX_NEIGHBOURS=8 + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${me25ls01.build_src_filter} + +<../examples/simple_room_server> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + +[env:Minewsemi_me25ls01_terminal_chat] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D ADVERT_NAME='"ME25LS01 Chat"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' + -D MAX_NEIGHBOURS=8 + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${me25ls01.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + +[env:Minewsemi_me25ls01_companion_radio_usb] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + ;-D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${me25ls01.build_src_filter} + + + +<../examples/companion_radio> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + diff --git a/variants/minewsemi_me25ls01/target.cpp b/variants/minewsemi_me25ls01/target.cpp new file mode 100644 index 00000000..13306762 --- /dev/null +++ b/variants/minewsemi_me25ls01/target.cpp @@ -0,0 +1,98 @@ +#include +#include "target.h" + +MinewsemiME25LS01Board board; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); + +WRAPPER_CLASS radio_driver(radio, board); + +VolatileRTCClock rtc_clock; +extern EnvironmentSensorManager sensors; +#if ENV_INCLUDE_GPS + #include + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); + EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); +#else + EnvironmentSensorManager sensors; +#endif + +#ifdef DISPLAY_CLASS + NullDisplayDriver display; +#endif + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +#ifdef RF_SWITCH_TABLE +static const uint32_t rfswitch_dios[Module::RFSWITCH_MAX_PINS] = { + RADIOLIB_LR11X0_DIO5, + RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, + RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, {LOW, LOW, LOW, LOW }}, + { LR11x0::MODE_RX, {HIGH, LOW, LOW, HIGH }}, + { LR11x0::MODE_TX, {HIGH, HIGH, LOW, HIGH }}, + { LR11x0::MODE_TX_HP, {LOW, HIGH, LOW, HIGH }}, + { LR11x0::MODE_TX_HF, {LOW, LOW, LOW, LOW }}, + { LR11x0::MODE_GNSS, {LOW, LOW, HIGH, LOW }}, + { LR11x0::MODE_WIFI, {LOW, LOW, LOW, LOW }}, + END_OF_MODE_TABLE, +}; +#endif + +bool radio_init() { + //rtc_clock.begin(Wire); + +#ifdef LR11X0_DIO3_TCXO_VOLTAGE + float tcxo = LR11X0_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + + SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); + SPI.begin(); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#ifdef RF_SWITCH_TABLE + radio.setRfSwitchTable(rfswitch_dios, rfswitch_table); +#endif +#ifdef RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} \ No newline at end of file diff --git a/variants/minewsemi_me25ls01/target.h b/variants/minewsemi_me25ls01/target.h new file mode 100644 index 00000000..aad55757 --- /dev/null +++ b/variants/minewsemi_me25ls01/target.h @@ -0,0 +1,29 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include "NullDisplayDriver.h" +#endif + +#ifdef DISPLAY_CLASS + extern NullDisplayDriver display; +#endif + +extern MinewsemiME25LS01Board board; +extern WRAPPER_CLASS radio_driver; +extern VolatileRTCClock rtc_clock; +extern EnvironmentSensorManager sensors; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/minewsemi_me25ls01/variant.cpp b/variants/minewsemi_me25ls01/variant.cpp new file mode 100644 index 00000000..5dbac9d3 --- /dev/null +++ b/variants/minewsemi_me25ls01/variant.cpp @@ -0,0 +1,70 @@ +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[PINS_COUNT + 1] = +{ + 0, // P0.00 + 1, // P0.01 + 2, // P0.02 + 3, // P0.03 + 4, // P0.04 + 5, // P0.05 + 6, // P0.06 + 7, // P0.07 + 8, // P0.08 + 9, // P0.09 + 10, // P0.10 + 11, // P0.11 + 12, // P0.12 + 13, // P0.13, PIN_SERIAL1_TX + 14, // P0.14, PIN_SERIAL1_RX + 15, // P0.15, PIN_SERIAL2_RX + 16, // P0.16, PIN_WIRE_SCL + 17, // P0.17, PIN_SERIAL2_TX + 18, // P0.18 + 19, // P0.19 + 20, // P0.20 + 21, // P0.21, PIN_WIRE_SDA + 22, // P0.22 + 23, // P0.23 + 24, // P0.24, + 25, // P0.25, + 26, // P0.26, + 27, // P0.27, + 28, // P0.28 + 29, // P0.29, + 30, // P0.30 + 31, // P0.31, BATTERY_PIN + 32, // P1.00 + 33, // P1.01, LORA_DIO_1 + 34, // P1.02 + 35, // P1.03, + 36, // P1.04 + 37, // P1.05, LR1110_EN + 38, // P1.06, + 39, // P1.07, + 40, // P1.08, PIN_SPI_MISO + 41, // P1.09, PIN_SPI_MOSI + 42, // P1.10, LORA_RESET + 43, // P1.11, GPS_EN + 44, // P1.12, GPS_SLEEP_INT + 45, // P1.13 + 46, // P1.14, GPS_RESETB + 47, // P1.15, PIN_GPS_RESET + 255, // NRFX_SPIM_PIN_NOT_USED +}; + +void initVariant() +{ + pinMode(BATTERY_PIN, INPUT); + pinMode(PIN_BUTTON1, INPUT); + + // pinMode(PIN_3V3_EN, OUTPUT); + // pinMode(PIN_3V3_ACC_EN, OUTPUT); + pinMode(LED_PIN, OUTPUT); + pinMode(P_LORA_TX_LED, OUTPUT); + + digitalWrite(LED_PIN, HIGH); + digitalWrite(P_LORA_TX_LED, LOW); +} diff --git a/variants/minewsemi_me25ls01/variant.h b/variants/minewsemi_me25ls01/variant.h new file mode 100644 index 00000000..a8bbbe3a --- /dev/null +++ b/variants/minewsemi_me25ls01/variant.h @@ -0,0 +1,94 @@ +#pragma once + +#include "WVariant.h" + +// Low frequency clock source +#define USE_LFXO // 32.768 kHz crystal oscillator +#define VARIANT_MCK (64000000ul) +// #define USE_LFRC // 32.768 kHz RC oscillator + +// Power +#define BATTERY_PIN (31) +#define BATTERY_IMMUTABLE +#define ADC_MULTIPLIER (2.0F) + +#define ADC_RESOLUTION (14) +#define BATTERY_SENSE_RES (12) + +// Number of pins +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (6) +#define NUM_ANALOG_OUTPUTS (0) + +// UART pin definition +#define PIN_SERIAL1_RX (14) // P0.14 +#define PIN_SERIAL1_TX (13) // P0.13 + +#define PIN_SERIAL2_RX (15) // P0.15 +#define PIN_SERIAL2_TX (17) // P0.17 + +// I2C pin definition +#define HAS_WIRE (1) +#define WIRE_INTERFACES_COUNT (1) + +#define PIN_WIRE_SDA (21) // P0.21 +#define PIN_WIRE_SCL (16) // P0.16 +#define I2C_NO_RESCAN + +// SPI pin definition +#define SPI_INTERFACES_COUNT (1) + +#define PIN_SPI_MISO (0 + 29) // P0.29 +#define PIN_SPI_MOSI (0 + 2) // P0.2 +#define PIN_SPI_SCK (32 + 15) // P1.15 +#define PIN_SPI_NSS (32 + 13) // P1.13 + +// Builtin LEDs +#define LED_BUILTIN (-1) +#define LED_RED (32 + 5) // P1.5 +#define LED_BLUE (32 + 7) // P1.7 +#define LED_PIN LED_BLUE +#define P_LORA_TX_LED LED_RED + +#define LED_STATE_ON HIGH + +// Builtin buttons + +#define PIN_BUTTON1 (0 + 27) // P0.6 +#define BUTTON_PIN PIN_BUTTON1 + +// LR1110 +#define LORA_DIO_1 (32 + 12) // P1.12 +#define LORA_DIO_2 (32 + 10) // P1.10 +#define LORA_NSS (PIN_SPI_NSS) // P1.13 +#define LORA_RESET (32 + 11) // P1.11 +#define LORA_BUSY (32 + 10) // P1.10 +#define LORA_SCLK (PIN_SPI_SCK) // P1.15 +#define LORA_MISO (PIN_SPI_MISO) // P0.29 +#define LORA_MOSI (PIN_SPI_MOSI) // P0.2 +#define LORA_CS PIN_SPI_NSS // P1.13 + +#define LR11X0_DIO_AS_RF_SWITCH true +#define LR11X0_DIO3_TCXO_VOLTAGE 1.6 + +#define LR1110_IRQ_PIN LORA_DIO_1 +#define LR1110_NRESET_PIN LORA_RESET +#define LR1110_BUSY_PIN LORA_DIO_2 +#define LR1110_SPI_NSS_PIN LORA_CS +#define LR1110_SPI_SCK_PIN LORA_SCLK +#define LR1110_SPI_MOSI_PIN LORA_MOSI +#define LR1110_SPI_MISO_PIN LORA_MISO + +// GPS +#define HAS_GPS 0 +#define GPS_RX_PIN PIN_SERIAL1_RX +#define GPS_TX_PIN PIN_SERIAL1_TX + +#define GPS_EN (-1) // P1.11 +#define GPS_RESET (-1) // P1.15 + +#define GPS_VRTC_EN (-1) // P0.8 +#define GPS_SLEEP_INT (-1) // P1.12 +#define GPS_RTC_INT (-1) // P0.15 +#define GPS_RESETB (-1) // P1.14 diff --git a/variants/nano_g2_ultra/platformio.ini b/variants/nano_g2_ultra/platformio.ini index 20928bdf..c2bb1f23 100644 --- a/variants/nano_g2_ultra/platformio.ini +++ b/variants/nano_g2_ultra/platformio.ini @@ -36,7 +36,7 @@ build_flags = -I src/helpers/ui -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 - -D BLE_PIN_CODE=0 + -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -D DISPLAY_CLASS=SH1106Display diff --git a/variants/rak3x72/target.cpp b/variants/rak3x72/target.cpp index d7070eae..446783aa 100644 --- a/variants/rak3x72/target.cpp +++ b/variants/rak3x72/target.cpp @@ -38,7 +38,7 @@ bool radio_init() { radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, STM32WL_TCXO_VOLTAGE, 0); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, STM32WL_TCXO_VOLTAGE, 0); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 9391f99b..86879ed7 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -6,8 +6,6 @@ board_check = true build_flags = ${nrf52840_base.build_flags} -I variants/rak4631 -D RAK_4631 - -D PIN_USER_BTN=9 - -D PIN_USER_BTN_ANA=31 -D PIN_BOARD_SCL=14 -D PIN_BOARD_SDA=13 -D PIN_OLED_RESET=-1 @@ -84,6 +82,8 @@ build_src_filter = ${rak4631.build_src_filter} extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -100,6 +100,8 @@ lib_deps = extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -120,6 +122,8 @@ lib_deps = extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -145,6 +149,8 @@ lib_deps = extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=1 ; -D MESH_PACKET_LOGGING=1 diff --git a/variants/sensecap_solar/SenseCapSolarBoard.cpp b/variants/sensecap_solar/SenseCapSolarBoard.cpp new file mode 100644 index 00000000..d6c044d1 --- /dev/null +++ b/variants/sensecap_solar/SenseCapSolarBoard.cpp @@ -0,0 +1,81 @@ +#include +#include "SenseCapSolarBoard.h" + +#include +#include + +static BLEDfu bledfu; + +static void connect_callback(uint16_t conn_handle) { + (void)conn_handle; + MESH_DEBUG_PRINTLN("BLE client connected"); +} + +static void disconnect_callback(uint16_t conn_handle, uint8_t reason) { + (void)conn_handle; + (void)reason; + + MESH_DEBUG_PRINTLN("BLE client disconnected"); +} + +void SenseCapSolarBoard::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + +#if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL) + Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL); +#endif + + Wire.begin(); + +#ifdef P_LORA_TX_LED + pinMode(P_LORA_TX_LED, OUTPUT); + digitalWrite(P_LORA_TX_LED, LOW); +#endif + + delay(10); // give sx1262 some time to power up +} + +bool SenseCapSolarBoard::startOTAUpdate(const char* id, char reply[]) { + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); + + Bluefruit.begin(1, 0); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + // Set the BLE device name + Bluefruit.setName("SENSECAP_SOLAR_OTA"); + + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); + + // Set up and start advertising + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); + + /* Start Advertising + - Enable auto advertising if disconnected + - Interval: fast mode = 20 ms, slow mode = 152.5 ms + - Timeout for fast mode is 30 seconds + - Start(timeout) with timeout = 0 will advertise forever (until connected) + + For recommended advertising interval + https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + + strcpy(reply, "OK - started"); + + return true; +} diff --git a/variants/sensecap_solar/SenseCapSolarBoard.h b/variants/sensecap_solar/SenseCapSolarBoard.h new file mode 100644 index 00000000..b1e5f8f1 --- /dev/null +++ b/variants/sensecap_solar/SenseCapSolarBoard.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +class SenseCapSolarBoard : public mesh::MainBoard { +protected: + uint8_t startup_reason; + +public: + void begin(); + uint8_t getStartupReason() const override { return startup_reason; } + +#if defined(P_LORA_TX_LED) + void onBeforeTransmit() override { + digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on + } + void onAfterTransmit() override { + digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off + } +#endif + + uint16_t getBattMilliVolts() override { + digitalWrite(VBAT_ENABLE, LOW); + int adcvalue = 0; + analogReadResolution(12); + analogReference(AR_INTERNAL_3_0); + delay(10); + adcvalue = analogRead(BATTERY_PIN); + return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096; + } + + const char* getManufacturerName() const override { + return "Seeed SenseCap Solar"; + } + + void reboot() override { + NVIC_SystemReset(); + } + + bool startOTAUpdate(const char* id, char reply[]) override; +}; diff --git a/variants/sensecap_solar/platformio.ini b/variants/sensecap_solar/platformio.ini new file mode 100644 index 00000000..281f6688 --- /dev/null +++ b/variants/sensecap_solar/platformio.ini @@ -0,0 +1,75 @@ +[SenseCap_Solar] +extends = nrf52_base +board = seeed_sensecap_solar +board_build.ldscript = boards/nrf52840_s140_v7.ld +build_flags = ${nrf52_base.build_flags} + -I lib/nrf52/s140_nrf52_7.3.0_API/include + -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52 + -I variants/sensecap_solar + -I src/helpers/nrf52 + -D NRF52_PLATFORM=1 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D P_LORA_TX_LED=12 + -D P_LORA_DIO_1=1 + -D P_LORA_RESET=2 + -D P_LORA_BUSY=3 + -D P_LORA_NSS=4 + -D LORA_TX_POWER=22 + -D SX126X_RXEN=5 + -D SX126X_TXEN=RADIOLIB_NC + -D SX126X_DIO2_AS_RF_SWITCH=1 + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_BMP280=1 + -D ENV_INCLUDE_SHTC3=1 + -D ENV_INCLUDE_LPS22HB=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 +build_src_filter = ${nrf52_base.build_src_filter} + + + + + + + +<../variants/SenseCap_Solar> +debug_tool = jlink +upload_protocol = nrfutil +lib_deps = + ${nrf52_base.lib_deps} + rweather/Crypto @ ^0.4.0 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 + adafruit/Adafruit BMP280 Library @ ^2.6.8 + adafruit/Adafruit SHTC3 Library @ ^1.0.1 + arduino-libraries/Arduino_LPS22HB @ ^1.0.2 + +[env:SenseCap_Solar_repeater] +extends = SenseCap_Solar +build_flags = + ${SenseCap_Solar.build_flags} + -D ADVERT_NAME='"SenseCap_Solar Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${SenseCap_Solar.build_src_filter} + +<../examples/simple_repeater/main.cpp> + +[env:SenseCap_Solar_room_server] +extends = SenseCap_Solar +build_flags = + ${SenseCap_Solar.build_flags} + -D ADVERT_NAME='"SenseCap_Solar Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${SenseCap_Solar.build_src_filter} + +<../examples/simple_room_server/main.cpp> \ No newline at end of file diff --git a/variants/sensecap_solar/target.cpp b/variants/sensecap_solar/target.cpp new file mode 100644 index 00000000..6bd7d31a --- /dev/null +++ b/variants/sensecap_solar/target.cpp @@ -0,0 +1,39 @@ +#include +#include "target.h" +#include + +SenseCapSolarBoard board; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); + +WRAPPER_CLASS radio_driver(radio, board); + +VolatileRTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +EnvironmentSensorManager sensors; + +bool radio_init() { + rtc_clock.begin(Wire); + + return radio.std_init(&SPI); +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/sensecap_solar/target.h b/variants/sensecap_solar/target.h new file mode 100644 index 00000000..63506951 --- /dev/null +++ b/variants/sensecap_solar/target.h @@ -0,0 +1,21 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#include + +extern SenseCapSolarBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern EnvironmentSensorManager sensors; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/sensecap_solar/variant.cpp b/variants/sensecap_solar/variant.cpp new file mode 100644 index 00000000..2b3ca305 --- /dev/null +++ b/variants/sensecap_solar/variant.cpp @@ -0,0 +1,69 @@ +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = { + // D0 .. D10 - Peripheral control pins + 2, // D0 P0.02 (A0) GNSS_WAKEUP + 3, // D1 P0.03 (A1) LORA_DIO1 + 28, // D2 P0.28 (A2) LORA_RESET + 29, // D3 P0.29 (A3) LORA_BUSY + 4, // D4 P0.04 (A4/SDA) LORA_CS + 5, // D5 P0.05 (A5/SCL) LORA_SW + 43, // D6 P1.11 (UART_TX) GNSS_TX + 44, // D7 P1.12 (UART_RX) GNSS_RX + 45, // D8 P1.13 (SPI_SCK) LORA_SCK + 46, // D9 P1.14 (SPI_MISO) LORA_MISO + 47, // D10 P1.15 (SPI_MOSI) LORA_MOSI + + // D11-D12 - LED outputs + 15, // D11 P0.15 User LED + 19, // D12 P0.19 Breathing LED + + // D13 - User input + 33, // D13 P1.01 User Button + + // D14-D15 - Grove/NFC interface + 9, // D14 P0.09 NFC1/GROVE_D1 + 10, // D15 P0.10 NFC2/GROVE_D0 + + // D16 - Power management + // 31, // D16 P0.31 VBAT_ADC (Battery voltage) + 31, // D16 P0.31 VBAT_ADC (Battery voltage) + // D17 - GNSS control + 35, // D17 P1.03 GNSS_RESET + + 37, // D18 P1.05 GNSS_ENABLE + 14, // D19 P0.14 BAT_READ + 39, // D20 P1.07 USER_BUTTON + + // + 21, // D21 P0.21 (QSPI_SCK) + 25, // D22 P0.25 (QSPI_CSN) + 20, // D23 P0.20 (QSPI_SIO_0 DI) + 24, // D24 P0.24 (QSPI_SIO_1 DO) + 22, // D25 P0.22 (QSPI_SIO_2 WP) + 23, // D26 P0.23 (QSPI_SIO_3 HOLD) +}; + +void initVariant() { + pinMode(GPS_EN, OUTPUT); + digitalWrite(GPS_EN, LOW); + + pinMode(BATTERY_PIN, INPUT); + pinMode(VBAT_ENABLE, OUTPUT); + digitalWrite(VBAT_ENABLE, LOW); + + pinMode(PIN_QSPI_CS, OUTPUT); + digitalWrite(PIN_QSPI_CS, HIGH); + + pinMode(LED_GREEN, OUTPUT); + digitalWrite(LED_GREEN, LOW); + + pinMode(LED_BLUE, OUTPUT); + digitalWrite(LED_BLUE, LOW); + + pinMode(GPS_EN, OUTPUT); + digitalWrite(GPS_EN, HIGH); +} diff --git a/variants/sensecap_solar/variant.h b/variants/sensecap_solar/variant.h new file mode 100644 index 00000000..76494f48 --- /dev/null +++ b/variants/sensecap_solar/variant.h @@ -0,0 +1,85 @@ +#ifndef _SEEED_SENSECAP_SOLAR_H_ +#define _SEEED_SENSECAP_SOLAR_H_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#define PINS_COUNT (33) +#define NUM_DIGITAL_PINS (33) +#define NUM_ANALOG_INPUTS (8) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED (12) +#define LED_PWR (PINS_COUNT) + +#define LED_BUILTIN (PIN_LED) + +#define LED_RED (PINS_COUNT) +#define LED_GREEN (12) +#define LED_BLUE (11) + +#define LED_STATE_ON (1) // State when LED is litted + +// Buttons +#define PIN_BUTTON1 (13) +#define PIN_BUTTON2 (20) + +#define VBAT_ENABLE (19) // Output LOW to enable reading of the BAT voltage. + +// Analog pins +#define BATTERY_PIN (16) // Read the BAT voltage. +#define AREF_VOLTAGE (3.0F) +#define ADC_MULTIPLIER (3.0F) // 1M, 512k divider bridge +#define ADC_RESOLUTION (12) + +// Serial interfaces +#define PIN_SERIAL1_RX (7) +#define PIN_SERIAL1_TX (6) + +// SPI Interfaces +#define SPI_INTERFACES_COUNT (1) + +#define PIN_SPI_MISO (9) +#define PIN_SPI_MOSI (10) +#define PIN_SPI_SCK (8) + +// Lora SPI is on SPI0 +#define P_LORA_SCLK PIN_SPI_SCK +#define P_LORA_MISO PIN_SPI_MISO +#define P_LORA_MOSI PIN_SPI_MOSI + +// Wire Interfaces +#define WIRE_INTERFACES_COUNT (1) + +#define PIN_WIRE_SDA (14) +#define PIN_WIRE_SCL (15) + +// GPS L76KB +#define GPS_BAUDRATE 9600 +#define GPS_THREAD_INTERVAL 50 +#define PIN_GPS_TX PIN_SERIAL1_RX +#define PIN_GPS_RX PIN_SERIAL1_TX +#define PIN_GPS_STANDBY (0) +#define GPS_EN (18) + +// QSPI Pins +#define PIN_QSPI_SCK (21) +#define PIN_QSPI_CS (22) +#define PIN_QSPI_IO0 (23) +#define PIN_QSPI_IO1 (24) +#define PIN_QSPI_IO2 (25) +#define PIN_QSPI_IO3 (26) + +#define EXTERNAL_FLASH_DEVICES P25Q16H +#define EXTERNAL_FLASH_USE_QSPI + +#endif \ No newline at end of file diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index 49ae26eb..06509c4f 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -54,14 +54,15 @@ bool radio_init() { SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); SPI.begin(); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); Serial.println(status); return false; // fail } - radio.setCRC(1); + radio.setCRC(2); + radio.explicitHeader(); #ifdef RF_SWITCH_TABLE radio.setRfSwitchTable(rfswitch_dios, rfswitch_table); diff --git a/variants/wio-e5-dev/target.cpp b/variants/wio-e5-dev/target.cpp index 8ccbe384..42e900e4 100644 --- a/variants/wio-e5-dev/target.cpp +++ b/variants/wio-e5-dev/target.cpp @@ -35,7 +35,7 @@ bool radio_init() { radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, 1.7, 0); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, 1.7, 0); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/variants/wio-e5-mini/target.cpp b/variants/wio-e5-mini/target.cpp index 6c045dd5..0e2358b8 100644 --- a/variants/wio-e5-mini/target.cpp +++ b/variants/wio-e5-mini/target.cpp @@ -33,7 +33,7 @@ bool radio_init() { radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, 1.7, 0); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, 1.7, 0); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/variants/xiao_c3/platformio.ini b/variants/xiao_c3/platformio.ini index 55baf2b8..b5bf1e16 100644 --- a/variants/xiao_c3/platformio.ini +++ b/variants/xiao_c3/platformio.ini @@ -1,6 +1,27 @@ [Xiao_esp32_C3] extends = esp32_base board = seeed_xiao_esp32c3 +build_flags = + ${esp32_base.build_flags} + -I variants/xiao_c3 + -D ESP32_CPU_FREQ=80 + -D PIN_VBAT_READ=D0 + -D P_LORA_DIO_1=D1 + -D P_LORA_NSS=D4 + -D P_LORA_RESET=D2 + -D P_LORA_BUSY=D3 + -D PIN_BOARD_SDA=D6 + -D PIN_BOARD_SCL=D7 + -D SX126X_RXEN=D5 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_CURRENT_LIMIT=140 +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/xiao_c3> + +[Xiao_esp32_C3_custom] +extends = esp32_base +board = seeed_xiao_esp32c3 build_flags = ${esp32_base.build_flags} -I variants/xiao_c3 @@ -22,6 +43,72 @@ build_src_filter = ${esp32_base.build_src_filter} [env:Xiao_C3_Repeater_sx1262] extends = Xiao_esp32_C3 +build_src_filter = ${Xiao_esp32_C3.build_src_filter} + +<../examples/simple_repeater/main.cpp> +build_flags = + ${Xiao_esp32_C3.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D SX126X_RX_BOOSTED_GAIN=1 + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Xiao C3 Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_esp32_C3.lib_deps} + ${esp32_ota.lib_deps} + +[env:Xiao_C3_companion_radio_ble] +extends = Xiao_esp32_C3 +build_src_filter = ${Xiao_esp32_C3.build_src_filter} + +<../examples/companion_radio> + + +build_flags = + ${Xiao_esp32_C3.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D SX126X_RX_BOOSTED_GAIN=1 + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D OFFLINE_QUEUE_SIZE=256 + ; -D BLE_DEBUG_LOGGING=1 + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_esp32_C3.lib_deps} + ${esp32_ota.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Xiao_C3_companion_radio_usb] +extends = Xiao_esp32_C3 +build_src_filter = ${Xiao_esp32_C3.build_src_filter} + +<../examples/companion_radio> + + +build_flags = + ${Xiao_esp32_C3.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D SX126X_RX_BOOSTED_GAIN=1 + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D OFFLINE_QUEUE_SIZE=256 + ; -D BLE_DEBUG_LOGGING=1 + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_esp32_C3.lib_deps} + ${esp32_ota.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Xiao_C3_Repeater_sx1262_custom] +extends = Xiao_esp32_C3_custom build_src_filter = ${Xiao_esp32_C3.build_src_filter} +<../examples/simple_repeater/main.cpp> build_flags = @@ -41,8 +128,8 @@ lib_deps = ${Xiao_esp32_C3.lib_deps} ${esp32_ota.lib_deps} -[env:Xiao_C3_Repeater_sx1268] -extends = Xiao_esp32_C3 +[env:Xiao_C3_Repeater_sx1268_custom] +extends = Xiao_esp32_C3_custom build_src_filter = ${Xiao_esp32_C3.build_src_filter} +<../examples/simple_repeater/main.cpp> build_flags = @@ -59,4 +146,4 @@ build_flags = ; -D MESH_DEBUG=1 lib_deps = ${Xiao_esp32_C3.lib_deps} - ${esp32_ota.lib_deps} + ${esp32_ota.lib_deps} \ No newline at end of file diff --git a/src/helpers/nrf52/XiaoNrf52Board.cpp b/variants/xiao_nrf52/XiaoNrf52Board.cpp similarity index 100% rename from src/helpers/nrf52/XiaoNrf52Board.cpp rename to variants/xiao_nrf52/XiaoNrf52Board.cpp diff --git a/src/helpers/nrf52/XiaoNrf52Board.h b/variants/xiao_nrf52/XiaoNrf52Board.h similarity index 92% rename from src/helpers/nrf52/XiaoNrf52Board.h rename to variants/xiao_nrf52/XiaoNrf52Board.h index e6c8e7f7..60b9f5bb 100644 --- a/src/helpers/nrf52/XiaoNrf52Board.h +++ b/variants/xiao_nrf52/XiaoNrf52Board.h @@ -5,20 +5,19 @@ #ifdef XIAO_NRF52 -// LoRa radio module pins for Seeed Xiao-nrf52 +// redefine lora pins if using the S3 variant of SX1262 board #ifdef SX1262_XIAO_S3_VARIANT #undef P_LORA_DIO_1 #undef P_LORA_BUSY #undef P_LORA_RESET #undef P_LORA_NSS + #undef SX126X_RXEN #define P_LORA_DIO_1 D0 #define P_LORA_BUSY D1 #define P_LORA_RESET D2 #define P_LORA_NSS D3 + #define SX126X_RXEN D4 #endif -//#define SX126X_POWER_EN 37 - - class XiaoNrf52Board : public mesh::MainBoard { protected: diff --git a/variants/xiao_nrf52/platformio.ini b/variants/xiao_nrf52/platformio.ini index c4934e04..bba3e632 100644 --- a/variants/xiao_nrf52/platformio.ini +++ b/variants/xiao_nrf52/platformio.ini @@ -50,8 +50,7 @@ build_flags = ${nrf52840_xiao.build_flags} -D ENV_INCLUDE_INA219=1 build_src_filter = ${nrf52840_xiao.build_src_filter} + - + - + + + +<../variants/xiao_nrf52> debug_tool = jlink upload_protocol = nrfutil diff --git a/variants/xiao_nrf52/target.h b/variants/xiao_nrf52/target.h index eb299006..c8c6a42a 100644 --- a/variants/xiao_nrf52/target.h +++ b/variants/xiao_nrf52/target.h @@ -3,7 +3,7 @@ #define RADIOLIB_STATIC_ONLY 1 #include #include -#include +#include #include #include #include diff --git a/variants/xiao_rp2040/platformio.ini b/variants/xiao_rp2040/platformio.ini new file mode 100644 index 00000000..960fdbba --- /dev/null +++ b/variants/xiao_rp2040/platformio.ini @@ -0,0 +1,104 @@ +[Xiao_rp2040] +extends = rp2040_base + +board = seeed_xiao_rp2040 +board_build.filesystem_size = 0.5m + +build_flags = ${rp2040_base.build_flags} + -I variants/xiao_rp2040 + -D SX126X_CURRENT_LIMIT=140 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D SX126X_RX_BOOSTED_GAIN=1 +; Debug options + ; -D DEBUG_RP2040_WIRE=1 + ; -D DEBUG_RP2040_SPI=1 + ; -D DEBUG_RP2040_CORE=1 + ; -D RADIOLIB_DEBUG_SPI=1 + ; -D DEBUG_RP2040_PORT=Serial + +build_src_filter = ${rp2040_base.build_src_filter} + + + +<../variants/xiao_rp2040> + +lib_deps = ${rp2040_base.lib_deps} + +[env:Xiao_rp2040_Repeater] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D ADVERT_NAME='"Xiao Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/simple_repeater> + +[env:Xiao_rp2040_room_server] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D ADVERT_NAME='"Xiao Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/simple_room_server> + +[env:Xiao_rp2040_companion_radio_usb] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 +; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/companion_radio> +lib_deps = ${Xiao_rp2040.lib_deps} + densaugeo/base64 @ ~1.4.0 + +; [env:Xiao_rp2040_companion_radio_ble] +; extends = Xiao_rp2040 +; build_flags = ${Xiao_rp2040.build_flags} +; -D MAX_CONTACTS=100 +; -D MAX_GROUP_CHANNELS=8 +; -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; ; -D MESH_PACKET_LOGGING=1 +; ; -D MESH_DEBUG=1 +; build_src_filter = ${Xiao_rp2040.build_src_filter} +; +<../examples/companion_radio> +; lib_deps = ${Xiao_rp2040.lib_deps} +; densaugeo/base64 @ ~1.4.0 + +; [env:Xiao_rp2040_companion_radio_wifi] +; extends = Xiao_rp2040 +; build_flags = ${Xiao_rp2040.build_flags} +; -D MAX_CONTACTS=100 +; -D MAX_GROUP_CHANNELS=8 +; -D WIFI_DEBUG_LOGGING=1 +; -D WIFI_SSID='"myssid"' +; -D WIFI_PWD='"mypwd"' +; ; -D MESH_PACKET_LOGGING=1 +; ; -D MESH_DEBUG=1 +; build_src_filter = ${Xiao_rp2040.build_src_filter} +; +<../examples/companion_radio> +; lib_deps = ${Xiao_rp2040.lib_deps} +; densaugeo/base64 @ ~1.4.0 + +[env:Xiao_rp2040_terminal_chat] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> +lib_deps = ${Xiao_rp2040.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/xiao_rp2040/target.cpp b/variants/xiao_rp2040/target.cpp new file mode 100644 index 00000000..a801aae8 --- /dev/null +++ b/variants/xiao_rp2040/target.cpp @@ -0,0 +1,71 @@ +#include "target.h" + +#include +#include + +XiaoRP2040Board board; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); + +WRAPPER_CLASS radio_driver(radio, board); + +VolatileRTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +SensorManager sensors; + +#ifndef LORA_CR +#define LORA_CR 5 +#endif + +bool radio_init() { + rtc_clock.begin(Wire); + +#ifdef SX126X_DIO3_TCXO_VOLTAGE + float tcxo = SX126X_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#ifdef SX126X_CURRENT_LIMIT + radio.setCurrentLimit(SX126X_CURRENT_LIMIT); +#endif + +#ifdef SX126X_DIO2_AS_RF_SWITCH + radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); +#endif + +#ifdef SX126X_RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/xiao_rp2040/target.h b/variants/xiao_rp2040/target.h new file mode 100644 index 00000000..6a3c192b --- /dev/null +++ b/variants/xiao_rp2040/target.h @@ -0,0 +1,21 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 + +#include +#include +#include +#include +#include +#include + +extern XiaoRP2040Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager sensors; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity();