From 0959e64d1133ee99e863c789a5cc15a43ea126d2 Mon Sep 17 00:00:00 2001 From: Florent Date: Tue, 26 Aug 2025 13:28:42 +0200 Subject: [PATCH 1/5] lib_build: add UI_FLAVOR and some cleanup --- build_as_lib.py | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/build_as_lib.py b/build_as_lib.py index 4e8eea57..d8e95378 100644 --- a/build_as_lib.py +++ b/build_as_lib.py @@ -15,28 +15,14 @@ src_filter = [ # add build and include dirs according to CPPDEFINES for item in menv.get("CPPDEFINES", []): - # STM32 - if isinstance(item, str) and item == "STM32_PLATFORM": - menv.Append(CPPPATH=[realpath("src/helpers/stm32")]) - menv.Append(BUILD_FLAGS=["-I src/helpers/stm32"]) + # PLATFORM HANDLING + if item == "STM32_PLATFORM": src_filter.append("+") - - # ESP32 - elif isinstance(item, str) and item == "ESP32": - menv.Append(CPPPATH=[realpath("src/helpers/esp32")]) - menv.Append(BUILD_FLAGS=["-I src/helpers/esp32"]) + elif item == "ESP32": src_filter.append("+") - - # NRF52 - elif isinstance(item, str) and item == "NRF52_PLATFORM": - menv.Append(CPPPATH=[realpath("src/helpers/nrf52")]) - menv.Append(BUILD_FLAGS=["-I src/helpers/nrf52"]) + elif item == "NRF52_PLATFORM": src_filter.append("+") - - # RP2040 - elif isinstance(item, str) and item == "RP2040_PLATFORM": - menv.Append(CPPPATH=[realpath("src/helpers/rp2040")]) - menv.Append(BUILD_FLAGS=["-I src/helpers/rp2040"]) + elif item == "RP2040_PLATFORM": src_filter.append("+") # DISPLAY HANDLING @@ -50,19 +36,29 @@ for item in menv.get("CPPDEFINES", []): # VARIANTS HANDLING elif isinstance(item, tuple) and item[0] == "MC_VARIANT": variant_name = item[1] - menv.Append(BUILD_FLAGS=[f"-I variants/{variant_name}"]) src_filter.append(f"+<../variants/{variant_name}>") # INCLUDE EXAMPLE CODE IN BUILD (to provide your own support files without touching the tree) elif isinstance(item, tuple) and item[0] == "BUILD_EXAMPLE": example_name = item[1] - src_filter.append(f"+<../examples/{example_name}>") + src_filter.append(f"+<../examples/{example_name}/*.cpp>") # EXCLUDE A SOURCE FILE FROM AN EXAMPLE (must be placed after example name or boom) elif isinstance(item, tuple) and item[0] == "EXCLUDE_FROM_EXAMPLE": exclude_name = item[1] + if example_name is None: + print("***** PLEASE DEFINE EXAMPLE FIRST *****") + break src_filter.append(f"-<../examples/{example_name}/{exclude_name}>") + # DEAL WITH UI VARIANT FOR AN EXAMPLE + elif isinstance(item, tuple) and item[0] == "MC_UI_FLAVOR": + ui_flavor = item[1] + if example_name is None: + print("***** PLEASE DEFINE EXAMPLE FIRST *****") + break + src_filter.append(f"+<../examples/{example_name}/{ui_flavor}/*.cpp>") + menv.Replace(SRC_FILTER=src_filter) #print (menv.Dump()) From 6536e9931d82faaf129bfd716777c951a45b9a6e Mon Sep 17 00:00:00 2001 From: ave Date: Tue, 26 Aug 2025 21:30:56 +0200 Subject: [PATCH 2/5] add why2025 badge as a target --- variants/xiao_c6/platformio.ini | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/variants/xiao_c6/platformio.ini b/variants/xiao_c6/platformio.ini index fdf0f337..602bd6ae 100644 --- a/variants/xiao_c6/platformio.ini +++ b/variants/xiao_c6/platformio.ini @@ -121,3 +121,65 @@ build_src_filter = ${Meshimi.build_src_filter} lib_deps = ${Meshimi.lib_deps} densaugeo/base64 @ ~1.4.0 + +; WHY2025 badge variant +; requires soldering 2 pins between the esp32-C6 and the lora chip as shown here: https://wiki.why2025.org/Project:Meshtastic_on_the_WHY2025_badge +; also requires wiping the esp32-P4 +[WHY2025_badge] +extends = Xiao_C6 +board_build.partitions = default_8MB.csv +board_upload.flash_size = 8MB +board_upload.maximum_size = 8388608 +build_flags = + ${Xiao_C6.build_flags} + -D P_LORA_SCLK=6 + -D P_LORA_MISO=2 + -D P_LORA_MOSI=7 + -D P_LORA_NSS=4 + -D P_LORA_DIO_1=5 + -D P_LORA_BUSY=11 + -D P_LORA_RESET=1 + -D SX126X_TXEN=3 + -UPIN_BOARD_SDA + -UPIN_BOARD_SCL + -UP_LORA_TX_LED + -USX126X_RXEN + -USX126X_DIO2_AS_RF_SWITCH + -USX126X_DIO3_TCXO_VOLTAGE + +[env:WHY2025_badge_Repeater] +extends = WHY2025_badge +build_src_filter = ${WHY2025_badge.build_src_filter} + +<../examples/simple_repeater/main.cpp> +build_flags = + ${WHY2025_badge.build_flags} + -D ADVERT_NAME='"WHY2025 Badge 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 = + ${WHY2025_badge.lib_deps} +; ${esp32_ota.lib_deps} + +[env:WHY2025_badge_companion_radio_ble] +extends = WHY2025_badge +build_flags = ${WHY2025_badge.build_flags} + -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 ENABLE_PRIVATE_KEY_IMPORT=1 + -D ENABLE_PRIVATE_KEY_EXPORT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${WHY2025_badge.build_src_filter} + + + - + +<../examples/companion_radio/*.cpp> +lib_deps = + ${WHY2025_badge.lib_deps} + densaugeo/base64 @ ~1.4.0 From c10b387e6338c0dfb9439b00c0d7d442a39e7542 Mon Sep 17 00:00:00 2001 From: 446564 Date: Wed, 27 Aug 2025 10:30:56 -0700 Subject: [PATCH 3/5] add remaining roles to t1000e usb companion, repeater and room server --- variants/t1000-e/platformio.ini | 63 ++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/variants/t1000-e/platformio.ini b/variants/t1000-e/platformio.ini index 2811e243..c555a735 100644 --- a/variants/t1000-e/platformio.ini +++ b/variants/t1000-e/platformio.ini @@ -34,6 +34,67 @@ build_src_filter = ${nrf52840_t1000e.build_src_filter} debug_tool = jlink upload_protocol = nrfutil +[env:t1000e_repeater] +extends = t1000-e +build_flags = ${t1000-e.build_flags} + -I examples/companion_radio/ui-orig + -D ADVERT_NAME='"t1000-e 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 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${t1000-e.build_src_filter} + +<../examples/simple_repeater> +lib_deps = ${t1000-e.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 + +[env:t1000e_room_server] +extends = t1000-e +build_flags = ${t1000-e.build_flags} + -I examples/companion_radio/ui-orig + -D ADVERT_NAME='"t1000-e 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 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${t1000-e.build_src_filter} + +<../examples/simple_room_server> +lib_deps = ${t1000-e.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 + +[env:t1000e_companion_radio_usb] +extends = t1000-e +build_flags = ${t1000-e.build_flags} + -I examples/companion_radio/ui-orig + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -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 ; P1/5 - required for T1000-E +build_src_filter = ${t1000-e.build_src_filter} + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-orig/*.cpp> +lib_deps = ${t1000-e.lib_deps} + densaugeo/base64 @ ~1.4.0 + stevemarple/MicroNMEA @ ^2.0.6 + end2endzone/NonBlockingRTTTL@^1.3.0 + [env:t1000e_companion_radio_ble] extends = t1000-e build_flags = ${t1000-e.build_flags} @@ -58,4 +119,4 @@ build_src_filter = ${t1000-e.build_src_filter} lib_deps = ${t1000-e.lib_deps} densaugeo/base64 @ ~1.4.0 stevemarple/MicroNMEA @ ^2.0.6 - end2endzone/NonBlockingRTTTL@^1.3.0 \ No newline at end of file + end2endzone/NonBlockingRTTTL@^1.3.0 From 136f733df52c8e3e801fec5534261fa42357f17d Mon Sep 17 00:00:00 2001 From: Florent Date: Wed, 27 Aug 2025 21:19:12 +0200 Subject: [PATCH 4/5] SensorMesh: add the possibility to receive msgs from admin --- examples/simple_sensor/SensorMesh.cpp | 99 +++++++++++++++++++-------- examples/simple_sensor/SensorMesh.h | 3 +- 2 files changed, 73 insertions(+), 29 deletions(-) diff --git a/examples/simple_sensor/SensorMesh.cpp b/examples/simple_sensor/SensorMesh.cpp index ce36e0c2..ad295501 100644 --- a/examples/simple_sensor/SensorMesh.cpp +++ b/examples/simple_sensor/SensorMesh.cpp @@ -613,6 +613,23 @@ void SensorMesh::getPeerSharedSecret(uint8_t* dest_secret, int peer_idx) { } } +void SensorMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) { + if (dest.out_path_len < 0) { + mesh::Packet* ack = createAck(ack_hash); + if (ack) sendFlood(ack, TXT_ACK_DELAY); + } else { + uint32_t d = TXT_ACK_DELAY; + if (getExtraAckTransmitCount() > 0) { + mesh::Packet* a1 = createMultiAck(ack_hash, 1); + if (a1) sendDirect(a1, dest.out_path, dest.out_path_len, d); + d += 300; + } + + mesh::Packet* a2 = createAck(ack_hash); + if (a2) sendDirect(a2, dest.out_path, dest.out_path_len, d); + } +} + void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) { int i = matching_peer_indexes[sender_idx]; if (i < 0 || i >= num_contacts) { @@ -656,38 +673,55 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i memcpy(&sender_timestamp, data, 4); // timestamp (by sender's RTC clock - which could be wrong) uint flags = (data[4] >> 2); // message attempt number, and other flags - if (!(flags == TXT_TYPE_CLI_DATA)) { - MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported text type received: flags=%02x", (uint32_t)flags); - } else if (sender_timestamp > from.last_timestamp) { // prevent replay attacks - from.last_timestamp = sender_timestamp; - from.last_activity = getRTCClock()->getCurrentTime(); + if (sender_timestamp > from.last_timestamp) { // prevent replay attacks + if (flags == TXT_TYPE_PLAIN) { + bool handled = handleIncomingMsg(from, sender_timestamp, &data[5], flags, len - 5); + if (handled) { // if msg was handled then send an ack + uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it + mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 5 + strlen((char *)&data[5]), from.id.pub_key, PUB_KEY_SIZE); - // len can be > original length, but 'text' will be padded with zeroes - data[len] = 0; // need to make a C string again, with null terminator - - uint8_t temp[166]; - char *command = (char *) &data[5]; - char *reply = (char *) &temp[5]; - handleCommand(sender_timestamp, command, reply); - - int text_len = strlen(reply); - if (text_len > 0) { - uint32_t timestamp = getRTCClock()->getCurrentTimeUnique(); - if (timestamp == sender_timestamp) { - // WORKAROUND: the two timestamps need to be different, in the CLI view - timestamp++; - } - memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique - temp[4] = (TXT_TYPE_CLI_DATA << 2); - - auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, from.id, secret, temp, 5 + text_len); - if (reply) { - if (from.out_path_len < 0) { - sendFlood(reply, CLI_REPLY_DELAY_MILLIS); + if (packet->isRouteFlood()) { + // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the ACK + mesh::Packet* path = createPathReturn(from.id, secret, packet->path, packet->path_len, + PAYLOAD_TYPE_ACK, (uint8_t *) &ack_hash, 4); + if (path) sendFlood(path, TXT_ACK_DELAY); } else { - sendDirect(reply, from.out_path, from.out_path_len, CLI_REPLY_DELAY_MILLIS); + sendAckTo(from, ack_hash); + } + } + } else if (flags == TXT_TYPE_CLI_DATA) { + from.last_timestamp = sender_timestamp; + from.last_activity = getRTCClock()->getCurrentTime(); + + // len can be > original length, but 'text' will be padded with zeroes + data[len] = 0; // need to make a C string again, with null terminator + + uint8_t temp[166]; + char *command = (char *) &data[5]; + char *reply = (char *) &temp[5]; + handleCommand(sender_timestamp, command, reply); + + int text_len = strlen(reply); + if (text_len > 0) { + uint32_t timestamp = getRTCClock()->getCurrentTimeUnique(); + if (timestamp == sender_timestamp) { + // WORKAROUND: the two timestamps need to be different, in the CLI view + timestamp++; + } + memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique + temp[4] = (TXT_TYPE_CLI_DATA << 2); + + auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, from.id, secret, temp, 5 + text_len); + if (reply) { + if (from.out_path_len < 0) { + sendFlood(reply, CLI_REPLY_DELAY_MILLIS); + } else { + sendDirect(reply, from.out_path, from.out_path_len, CLI_REPLY_DELAY_MILLIS); + } } } + } else { + MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported text type received: flags=%02x", (uint32_t)flags); } } else { MESH_DEBUG_PRINTLN("onPeerDataRecv: possible replay attack detected"); @@ -695,6 +729,15 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i } } +bool SensorMesh::handleIncomingMsg(ContactInfo& from, uint32_t timestamp, uint8_t* data, uint flags, size_t len) { + MESH_DEBUG_PRINT("handleIncomingMsg: unhandled msg from "); + #ifdef MESH_DEBUG + mesh::Utils::printHex(Serial, from.id.pub_key, PUB_KEY_SIZE); + Serial.printf(": %s\n", data); + #endif + return false; +} + bool SensorMesh::onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) { int i = matching_peer_indexes[sender_idx]; if (i < 0 || i >= num_contacts) { diff --git a/examples/simple_sensor/SensorMesh.h b/examples/simple_sensor/SensorMesh.h index 0d87617b..62c1867e 100644 --- a/examples/simple_sensor/SensorMesh.h +++ b/examples/simple_sensor/SensorMesh.h @@ -140,7 +140,8 @@ protected: void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override; bool onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override; void onAckRecv(mesh::Packet* packet, uint32_t ack_crc) override; - + virtual bool handleIncomingMsg(ContactInfo& from, uint32_t timestamp, uint8_t* data, uint flags, size_t len); + void sendAckTo(const ContactInfo& dest, uint32_t ack_hash); private: FILESYSTEM* _fs; unsigned long next_local_advert, next_flood_advert; From 789629f5f8a80f4599ab37a52664589179fc3a8b Mon Sep 17 00:00:00 2001 From: 446564 Date: Thu, 28 Aug 2025 08:13:33 -0700 Subject: [PATCH 5/5] remove display class from repeater and room --- variants/t1000-e/platformio.ini | 2 -- 1 file changed, 2 deletions(-) diff --git a/variants/t1000-e/platformio.ini b/variants/t1000-e/platformio.ini index c555a735..b1826139 100644 --- a/variants/t1000-e/platformio.ini +++ b/variants/t1000-e/platformio.ini @@ -47,7 +47,6 @@ build_flags = ${t1000-e.build_flags} ; -D MESH_DEBUG=1 -D RX_BOOSTED_GAIN=true -D RF_SWITCH_TABLE - -D DISPLAY_CLASS=NullDisplayDriver build_src_filter = ${t1000-e.build_src_filter} +<../examples/simple_repeater> lib_deps = ${t1000-e.lib_deps} @@ -66,7 +65,6 @@ build_flags = ${t1000-e.build_flags} ; -D MESH_DEBUG=1 -D RX_BOOSTED_GAIN=true -D RF_SWITCH_TABLE - -D DISPLAY_CLASS=NullDisplayDriver build_src_filter = ${t1000-e.build_src_filter} +<../examples/simple_room_server> lib_deps = ${t1000-e.lib_deps}