From fca16f1b71d13387b5e8e35eccd628ac6a1d03c3 Mon Sep 17 00:00:00 2001 From: 446564 Date: Sat, 13 Sep 2025 21:35:27 -0700 Subject: [PATCH 1/6] make offline queue channel messages mutable older channel messages can be overwritten, keeping other mssagage types this allows a user to be away for a long time and still get the most recent channel messages without losing any direct messages for exampe --- examples/companion_radio/MyMesh.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 04d5577e..4d891144 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -177,13 +177,29 @@ void MyMesh::updateContactFromFrame(ContactInfo &contact, uint32_t& last_mod, co void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) { if (offline_queue_len >= OFFLINE_QUEUE_SIZE) { - MESH_DEBUG_PRINTLN("ERROR: offline_queue is full!"); + MESH_DEBUG_PRINTLN("WARN: offline_queue is full!"); + int pos = 0; + while (pos < offline_queue_len) { + if ((offline_queue[pos].buf[0] == RESP_CODE_CHANNEL_MSG_RECV) || + offline_queue[pos].buf[0] == RESP_CODE_CHANNEL_MSG_RECV_V3) { + for (int i = pos; i < offline_queue_len; i++) { // delete oldest channel msg from queue + offline_queue[i] = offline_queue[i + 1]; + } + MESH_DEBUG_PRINTLN("INFO: removed oldest channel message from queue."); + offline_queue[offline_queue_len - 1].len = len; + memcpy(offline_queue[offline_queue_len - 1].buf, frame, len); + return; + } + pos++; + } + MESH_DEBUG_PRINTLN("INFO: no channel messages to remove from queue."); } else { offline_queue[offline_queue_len].len = len; memcpy(offline_queue[offline_queue_len].buf, frame, len); offline_queue_len++; } } + int MyMesh::getFromOfflineQueue(uint8_t frame[]) { if (offline_queue_len > 0) { // check offline queue size_t len = offline_queue[0].len; // take from top of queue From 736118fe6b55e91608b403914c61626b5210e6f7 Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 20 Sep 2025 10:58:02 +0800 Subject: [PATCH 2/6] Add tiny_relay variant files - platformio.ini: Build configuration for tiny relay variant - target.cpp/h: Hardware-specific implementation - variant.h: Variant identification header --- variants/tiny_relay/platformio.ini | 44 ++++++++++++++++ variants/tiny_relay/target.cpp | 82 ++++++++++++++++++++++++++++++ variants/tiny_relay/target.h | 59 +++++++++++++++++++++ variants/tiny_relay/variant.h | 5 ++ 4 files changed, 190 insertions(+) create mode 100644 variants/tiny_relay/platformio.ini create mode 100644 variants/tiny_relay/target.cpp create mode 100644 variants/tiny_relay/target.h create mode 100644 variants/tiny_relay/variant.h diff --git a/variants/tiny_relay/platformio.ini b/variants/tiny_relay/platformio.ini new file mode 100644 index 00000000..6816ed20 --- /dev/null +++ b/variants/tiny_relay/platformio.ini @@ -0,0 +1,44 @@ +[Tiny_Relay] +extends = stm32_base +board = tiny_relay +board_upload.maximum_size = 229376 ; 32kb for FS +build_flags = ${stm32_base.build_flags} + -D RADIO_CLASS=CustomSTM32WLx + -D WRAPPER_CLASS=CustomSTM32WLxWrapper + -D SPI_INTERFACES_COUNT=0 + -D RX_BOOSTED_GAIN=true +; -D STM32WL_TCXO_VOLTAGE=1.6 ; defaults to 0 if undef +; -D LORA_TX_POWER=14 ; Defaults to 22 for HP, 14 is for LP version + -D LORA_TX_POWER=22 ; Enable 22dBm transmission + -D MAX_LORA_TX_POWER=22 ; Allow setting up to 22dBm in companion radio + -I variants/tiny_relay +build_src_filter = ${stm32_base.build_src_filter} + +<../variants/tiny_relay> + +[env:Tiny_Relay-repeater] +extends = Tiny_Relay +build_flags = ${Tiny_Relay.build_flags} + -D ADVERT_NAME='"tiny_relay Repeater"' + -D ADMIN_PASSWORD='"password"' +build_src_filter = ${Tiny_Relay.build_src_filter} + +<../examples/simple_repeater/main.cpp> + +[env:Tiny_Relay-sensor] +extends = Tiny_Relay +build_flags = ${Tiny_Relay.build_flags} + -D ADVERT_NAME='"tiny_relay Sensor"' + -D ADMIN_PASSWORD='"password"' +build_src_filter = ${Tiny_Relay.build_src_filter} + +<../examples/simple_sensor> + +[env:Tiny_Relay_companion_radio_usb] +extends = Tiny_Relay +build_flags = ${Tiny_Relay.build_flags} +; -D FORMAT_FS=true + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D MAX_LORA_TX_POWER=22 +build_src_filter = ${Tiny_Relay.build_src_filter} + +<../examples/companion_radio/*.cpp> +lib_deps = ${Tiny_Relay.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/tiny_relay/target.cpp b/variants/tiny_relay/target.cpp new file mode 100644 index 00000000..f738ac17 --- /dev/null +++ b/variants/tiny_relay/target.cpp @@ -0,0 +1,82 @@ +#include "target.h" +#include +#include + +TinyRelayBoard board; + +RADIO_CLASS radio = new STM32WLx_Module(); + +WRAPPER_CLASS radio_driver(radio, board); + +static const uint32_t rfswitch_pins[] = {LORAWAN_RFSWITCH_PINS, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {LOW, HIGH}}, + {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, + END_OF_MODE_TABLE, +}; + +VolatileRTCClock rtc_clock; +SensorManager sensors; + +#ifndef LORA_CR +#define LORA_CR 5 +#endif + +#ifndef STM32WL_TCXO_VOLTAGE +// TCXO set to 0 for RAK3172 +#define STM32WL_TCXO_VOLTAGE 0 +#endif + +#ifndef LORA_TX_POWER +#define LORA_TX_POWER 22 +#endif + +bool radio_init() +{ + // rtc_clock.begin(Wire); + + 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, 16, + STM32WL_TCXO_VOLTAGE, 0); + + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + +#ifdef RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(RX_BOOSTED_GAIN); +#endif + + radio.setCRC(1); + + 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/tiny_relay/target.h b/variants/tiny_relay/target.h new file mode 100644 index 00000000..82747cdc --- /dev/null +++ b/variants/tiny_relay/target.h @@ -0,0 +1,59 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include + +#define PIN_VBAT_READ A0 +#define ADC_MULTIPLIER (5 * 1.73 * 1000) + +class TinyRelayBoard : public STM32Board +{ + public: + void begin() override + { + STM32Board::begin(); + pinMode(PA0, OUTPUT); + pinMode(PA1, OUTPUT); + } + + const char *getManufacturerName() const override { return "Tiny Relay"; } + + uint16_t getBattMilliVolts() override + { + analogReadResolution(12); + uint32_t raw = 0; + for (int i = 0; i < 8; i++) { + raw += analogRead(PIN_VBAT_READ); + } + return ((double)raw) * ADC_MULTIPLIER / 8 / 4096; + } + + void setGpio(uint32_t values) override + { + // set led values + digitalWrite(PA0, values & 1); + digitalWrite(PA1, (values & 2) >> 1); + } + + uint32_t getGpio() override + { + // get led value + return (digitalRead(PA1) << 1) | digitalRead(PA0); + } +}; + +extern TinyRelayBoard board; +extern WRAPPER_CLASS radio_driver; +extern VolatileRTCClock 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(); diff --git a/variants/tiny_relay/variant.h b/variants/tiny_relay/variant.h new file mode 100644 index 00000000..4405be0b --- /dev/null +++ b/variants/tiny_relay/variant.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +#undef RNG From b3af4d9c723e6c8ef8fe9706152b7328c97e61a0 Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 20 Sep 2025 10:59:36 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20tiny=5Frelay=20bo?= =?UTF-8?q?ard=20configuration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add board configuration for BB-STM32WL tiny relay variant with STM32WLE5CC MCU support including debug and upload protocols. --- boards/tiny_relay.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 boards/tiny_relay.json diff --git a/boards/tiny_relay.json b/boards/tiny_relay.json new file mode 100644 index 00000000..c2bfae14 --- /dev/null +++ b/boards/tiny_relay.json @@ -0,0 +1,33 @@ +{ + "build": { + "arduino": { + "variant_h": "variant_RAK3172_MODULE.h" + }, + "core": "stm32", + "cpu": "cortex-m4", + "extra_flags": "-DSTM32WL -DSTM32WLxx -DSTM32WLE5xx", + "framework_extra_flags": { + "arduino": "-DUSE_CM4_STARTUP_FILE -DARDUINO_RAK3172_MODULE" + }, + "f_cpu": "48000000L", + "mcu": "stm32wle5ccu", + "product_line": "STM32WLE5xx", + "variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U" + }, + "debug": { + "default_tools": ["stlink"], + "jlink_device": "STM32WLE5CC", + "openocd_target": "stm32wlx", + "svd_path": "STM32WLE5_CM4.svd" + }, + "frameworks": ["arduino"], + "name": "BB-STM32WL", + "upload": { + "maximum_ram_size": 65536, + "maximum_size": 262144, + "protocol": "stlink", + "protocols": ["stlink", "jlink"] + }, + "url": "YAOAO", + "vendor": "YAOYAO" +} From a1622bad752bcbc947acdb5fae962b52e37a0df7 Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 20 Sep 2025 14:07:22 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=94=97=20fix:=20update=20tiny=5Frelay?= =?UTF-8?q?=20board=20URL=20to=20proper=20STM32WLE5CC=20documentation=20li?= =?UTF-8?q?nk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- boards/tiny_relay.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/tiny_relay.json b/boards/tiny_relay.json index c2bfae14..517d11f0 100644 --- a/boards/tiny_relay.json +++ b/boards/tiny_relay.json @@ -28,6 +28,6 @@ "protocol": "stlink", "protocols": ["stlink", "jlink"] }, - "url": "YAOAO", + "url": "https://www.st.com/en/microcontrollers-microprocessors/stm32wle5cc.html", "vendor": "YAOYAO" } From 2922b62888aafd32093f75d61430d6ae548599ff Mon Sep 17 00:00:00 2001 From: taco Date: Sat, 20 Sep 2025 17:36:52 +1000 Subject: [PATCH 5/6] add bounds check to _countLfsBlock / _getLfsUsedBlockCount --- examples/companion_radio/DataStore.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 7631b905..f1adb05e 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -42,12 +42,17 @@ static File openWrite(FILESYSTEM* fs, const char* filename) { #endif } +#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + static uint32_t _ContactsChannelsTotalBlocks = 0; +#endif + void DataStore::begin() { #if defined(RP2040_PLATFORM) identity_store.begin(); #endif #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _ContactsChannelsTotalBlocks = _getContactsChannelsFS()->_getFS()->cfg->block_count; checkAdvBlobFile(); #if defined(EXTRAFS) || defined(QSPIFLASH) migrateToSecondaryFS(); @@ -74,14 +79,22 @@ void DataStore::begin() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) int _countLfsBlock(void *p, lfs_block_t block){ + if (block > _ContactsChannelsTotalBlocks) { + MESH_DEBUG_PRINTLN("ERROR: Block %d exceeds filesystem bounds - CORRUPTION DETECTED!", block); + return LFS_ERR_CORRUPT; // return error to abort lfs_traverse() gracefully + } lfs_size_t *size = (lfs_size_t*) p; *size += 1; - return 0; + return 0; } lfs_ssize_t _getLfsUsedBlockCount(FILESYSTEM* fs) { lfs_size_t size = 0; - lfs_traverse(fs->_getFS(), _countLfsBlock, &size); + int err = lfs_traverse(fs->_getFS(), _countLfsBlock, &size); + if (err) { + MESH_DEBUG_PRINTLN("ERROR: lfs_traverse() error: %d", err); + return 0; + } return size; } #endif From 52d5cc6068cb19a3d319f798714ee685fa786673 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 22 Sep 2025 15:01:28 +1000 Subject: [PATCH 6/6] * tidy and minor fix for offline queue deletion --- examples/companion_radio/MyMesh.cpp | 9 ++++++--- examples/companion_radio/MyMesh.h | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index e53ad378..509b0c63 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -175,14 +175,17 @@ void MyMesh::updateContactFromFrame(ContactInfo &contact, uint32_t& last_mod, co } } +bool MyMesh::Frame::isChannelMsg() const { + return buf[0] == RESP_CODE_CHANNEL_MSG_RECV || buf[0] == RESP_CODE_CHANNEL_MSG_RECV_V3; +} + void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) { if (offline_queue_len >= OFFLINE_QUEUE_SIZE) { MESH_DEBUG_PRINTLN("WARN: offline_queue is full!"); int pos = 0; while (pos < offline_queue_len) { - if ((offline_queue[pos].buf[0] == RESP_CODE_CHANNEL_MSG_RECV) || - offline_queue[pos].buf[0] == RESP_CODE_CHANNEL_MSG_RECV_V3) { - for (int i = pos; i < offline_queue_len; i++) { // delete oldest channel msg from queue + if (offline_queue[pos].isChannelMsg()) { + for (int i = pos; i < offline_queue_len - 1; i++) { // delete oldest channel msg from queue offline_queue[i] = offline_queue[i + 1]; } MESH_DEBUG_PRINTLN("INFO: removed oldest channel message from queue."); diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 0dc9ad61..20efb46b 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -198,6 +198,8 @@ private: struct Frame { uint8_t len; uint8_t buf[MAX_FRAME_SIZE]; + + bool isChannelMsg() const; }; int offline_queue_len; Frame offline_queue[OFFLINE_QUEUE_SIZE];