Merge branch 'dev' into double-acks

This commit is contained in:
Scott Powell
2025-07-08 22:14:48 +10:00
61 changed files with 2683 additions and 176 deletions

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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>
+<helpers/*.cpp>

View File

@@ -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)) {

View File

@@ -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));

View File

@@ -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(); }

View File

@@ -4,7 +4,7 @@
#include <helpers/RefCountedDigitalPin.h>
// 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

View File

@@ -0,0 +1,81 @@
#pragma once
#include <Arduino.h>
// 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 <driver/rtc_io.h>
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";
}
};

View File

@@ -0,0 +1,91 @@
#include <Arduino.h>
#include "MinewsemiME25LS01Board.h"
#include <Wire.h>
#include <bluefruit.h>
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;
}

View File

@@ -0,0 +1,88 @@
#pragma once
#include <MeshCore.h>
#include <Arduino.h>
// 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;
};

View File

@@ -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;
}

View File

@@ -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

View File

@@ -0,0 +1,30 @@
#include "XiaoRP2040Board.h"
#include <Arduino.h>
#include <Wire.h>
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;
}

View File

@@ -0,0 +1,75 @@
#pragma once
#include <Arduino.h>
#include <MeshCore.h>
// 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;
};

View File

@@ -24,6 +24,14 @@ static Adafruit_BME280 BME280;
static Adafruit_BMP280 BMP280;
#endif
#if ENV_INCLUDE_SHTC3
#include <Adafruit_SHTC3.h>
static Adafruit_SHTC3 SHTC3;
#endif
#if ENV_INCLUDE_LPS22HB
#include <Arduino_LPS22HB.h>
#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

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include "DisplayDriver.h"
#include <SPI.h>
#include <Wire.h>
#include <heltec-eink-modules.h>
// 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();
};

View File

@@ -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() {

View File

@@ -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

View File

@@ -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>
+<helpers/sensors>
@@ -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

View File

@@ -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}
+<helpers/ui/E213Display.cpp>
+<helpers/esp32/*.cpp>
+<../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}
+<helpers/ui/E213Display.cpp>
+<../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}
+<helpers/ui/E213Display.cpp>
+<../examples/simple_room_server>
lib_deps =
${Heltec_Wireless_Paper_base.lib_deps}
${esp32_ota.lib_deps}

View File

@@ -0,0 +1,45 @@
#include "target.h"
#include <Arduino.h>
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
}

View File

@@ -0,0 +1,27 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/HeltecV3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/E213Display.h>
#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();

View File

@@ -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() {

View File

@@ -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}
${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}

View File

@@ -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>
+<helpers/ui/SSD1306Display.cpp>
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>
+<helpers/ui/SSD1306Display.cpp>
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>
+<helpers/ui/SSD1306Display.cpp>
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>
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
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>
+<helpers/ui/SSD1306Display.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>
+<helpers/ui/SSD1306Display.cpp>
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>
+<helpers/ui/SSD1306Display.cpp>
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>
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
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>
+<helpers/ui/SSD1306Display.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>
+<helpers/ui/SSD1306Display.cpp>
lib_deps =
${Meshadventurer.lib_deps}
${esp32_ota.lib_deps}

View File

@@ -0,0 +1,119 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/sensors/MicroNMEALocationProvider.h>
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
}

View File

@@ -0,0 +1,46 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/MeshadventurerBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomSX1268Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
#include <helpers/sensors/LocationProvider.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#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();

View File

@@ -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

View File

@@ -0,0 +1,24 @@
#pragma once
#include <helpers/ui/DisplayDriver.h>
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() { }
};

View File

@@ -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}
+<helpers/*.cpp>
+<helpers/nrf52/MinewsemiME25LS01Board.cpp>
+<../variants/minewsemi_me25ls01>
+<helpers/sensors>
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}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../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}
+<helpers/nrf52/*.cpp>
+<../examples/companion_radio>
lib_deps = ${me25ls01.lib_deps}
adafruit/RTClib @ ^2.1.3

View File

@@ -0,0 +1,98 @@
#include <Arduino.h>
#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 <helpers/sensors/MicroNMEALocationProvider.h>
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
}

View File

@@ -0,0 +1,29 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/nrf52/MinewsemiME25LS01Board.h>
#include <helpers/CustomLR1110Wrapper.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/SensorManager.h>
#include <helpers/sensors/LocationProvider.h>
#include <helpers/sensors/EnvironmentSensorManager.h>
#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();

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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: ");

View File

@@ -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

View File

@@ -0,0 +1,81 @@
#include <Arduino.h>
#include "SenseCapSolarBoard.h"
#include <bluefruit.h>
#include <Wire.h>
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;
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <MeshCore.h>
#include <Arduino.h>
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;
};

View File

@@ -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}
+<helpers/*.cpp>
+<helpers/sensors>
+<helpers/nrf52/SenseCapSolarBoard.cpp>
+<../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>

View File

@@ -0,0 +1,39 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>
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
}

View File

@@ -0,0 +1,21 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <SenseCapSolarBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/sensors/EnvironmentSensorManager.h>
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();

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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: ");

View File

@@ -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: ");

View File

@@ -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>
+<helpers/esp32/*.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 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>
+<helpers/esp32/*.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 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}

View File

@@ -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:

View File

@@ -50,8 +50,7 @@ build_flags = ${nrf52840_xiao.build_flags}
-D ENV_INCLUDE_INA219=1
build_src_filter = ${nrf52840_xiao.build_src_filter}
+<helpers/*.cpp>
+<helpers/sensors>
+<helpers/nrf52/XiaoNrf52Board.cpp>
+<helpers/sensors>
+<../variants/xiao_nrf52>
debug_tool = jlink
upload_protocol = nrfutil

View File

@@ -3,7 +3,7 @@
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/nrf52/XiaoNrf52Board.h>
#include <XiaoNrf52Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/ArduinoHelpers.h>

View File

@@ -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}
+<helpers/rp2040/XiaoRP2040Board.cpp>
+<../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

View File

@@ -0,0 +1,71 @@
#include "target.h"
#include <Arduino.h>
#include <helpers/ArduinoHelpers.h>
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
}

View File

@@ -0,0 +1,21 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/SensorManager.h>
#include <helpers/rp2040/XiaoRP2040Board.h>
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();