From 5089268ef0100c84c5b080cf0e8b493f31290898 Mon Sep 17 00:00:00 2001 From: "Bence T." <3326575+tbb98@users.noreply.github.com> Date: Sat, 8 Mar 2025 00:04:43 +0100 Subject: [PATCH 01/39] Create packet_structure.md As mentioned by @mofosyne at issue #72 --- docs/packet_structure.md | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 docs/packet_structure.md diff --git a/docs/packet_structure.md b/docs/packet_structure.md new file mode 100644 index 00000000..a38c43ce --- /dev/null +++ b/docs/packet_structure.md @@ -0,0 +1,50 @@ +# Packet Structure + +| Field | Size (bytes) | Description | +|--------------|------------------------|-------------| +| `header` | 1 | Contains routing type, payload type, and payload version. | +| `payload_len` | 2 | Length of the payload in bytes. | +| `path_len` | 2 | Length of the path field in bytes. | +| `path` | `MAX_PATH_SIZE` | Stores the routing path if applicable. | +| `payload` | `MAX_PACKET_PAYLOAD` | The actual data being transmitted. | + +## Header Breakdown + +| Bits | Mask | Field | Description | +|-------|---------------|----------------|-------------| +| 0-1 | `0x03` | Route Type | Specifies the routing type (Flood, Direct, Reserved). | +| 2-5 | `0x0F` | Payload Type | Specifies the type of payload (Request, Response, Text, ACK, etc.). | +| 6-7 | `0x03` | Payload Version | Versioning of the payload format. | + +## Route Type Values + +| Value | Name | Description | +|--------|-------------------------|-------------| +| `0x00` | `ROUTE_TYPE_RESERVED1` | Reserved for future use. | +| `0x01` | `ROUTE_TYPE_FLOOD` | Flood routing mode (builds up path). | +| `0x02` | `ROUTE_TYPE_DIRECT` | Direct route (path is supplied). | +| `0x03` | `ROUTE_TYPE_RESERVED2` | Reserved for future use. | + +## Payload Type Values + +| Value | Name | Description | +|--------|-------------------------|-------------| +| `0x00` | `PAYLOAD_TYPE_REQ` | Request (destination/source hashes + MAC). | +| `0x01` | `PAYLOAD_TYPE_RESPONSE` | Response to REQ or ANON_REQ. | +| `0x02` | `PAYLOAD_TYPE_TXT_MSG` | Plain text message. | +| `0x03` | `PAYLOAD_TYPE_ACK` | Acknowledgment. | +| `0x04` | `PAYLOAD_TYPE_ADVERT` | Node advertisement. | +| `0x05` | `PAYLOAD_TYPE_GRP_TXT` | Group text message (unverified). | +| `0x06` | `PAYLOAD_TYPE_GRP_DATA` | Group datagram (unverified). | +| `0x07` | `PAYLOAD_TYPE_ANON_REQ` | Anonymous request. | +| `0x08` | `PAYLOAD_TYPE_PATH` | Returned path. | +| `0x0F` | `PAYLOAD_TYPE_RAW_CUSTOM` | Custom packet (raw bytes, custom encryption). | + +## Payload Version Values + +| Value | Name | Description | +|--------|---------------|-------------| +| `0x00` | `PAYLOAD_VER_1` | 1-byte src/dest hashes, 2-byte MAC. | +| `0x01` | `PAYLOAD_VER_2` | Future version (e.g., 2-byte hashes, 4-byte MAC). | +| `0x02` | `PAYLOAD_VER_3` | Future version. | +| `0x03` | `PAYLOAD_VER_4` | Future version. | From 9d53fc2679feb621682e3cb2411218730c5bcbde Mon Sep 17 00:00:00 2001 From: Matthew Sainsbury Date: Thu, 5 Jun 2025 20:16:18 -0700 Subject: [PATCH 02/39] corrections and style --- docs/packet_structure.md | 69 ++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/docs/packet_structure.md b/docs/packet_structure.md index a38c43ce..b02c3c33 100644 --- a/docs/packet_structure.md +++ b/docs/packet_structure.md @@ -1,50 +1,51 @@ # Packet Structure -| Field | Size (bytes) | Description | -|--------------|------------------------|-------------| -| `header` | 1 | Contains routing type, payload type, and payload version. | -| `payload_len` | 2 | Length of the payload in bytes. | -| `path_len` | 2 | Length of the path field in bytes. | -| `path` | `MAX_PATH_SIZE` | Stores the routing path if applicable. | -| `payload` | `MAX_PACKET_PAYLOAD` | The actual data being transmitted. | +| Field | Size (bytes) | Description | +|----------|----------------------------------|-----------------------------------------------------------| +| header | 1 | Contains routing type, payload type, and payload version. | +| path_len | 1 | Length of the path field in bytes. | +| path | up to 64 (`MAX_PATH_SIZE`) | Stores the routing path if applicable. | +| payload | up to 184 (`MAX_PACKET_PAYLOAD`) | The actual data being transmitted. | + +Note: see the [payloads doc](./payloads.md) for more information about the content of payload. ## Header Breakdown -| Bits | Mask | Field | Description | -|-------|---------------|----------------|-------------| -| 0-1 | `0x03` | Route Type | Specifies the routing type (Flood, Direct, Reserved). | -| 2-5 | `0x0F` | Payload Type | Specifies the type of payload (Request, Response, Text, ACK, etc.). | -| 6-7 | `0x03` | Payload Version | Versioning of the payload format. | +| Bits | Mask | Field | Description | +|-------|--------|-----------------|-----------------------------------------------| +| 0-1 | `0x03` | Route Type | Flood, Direct, Reserved - see below. | +| 2-5 | `0x0F` | Payload Type | Request, Response, ACK, etc. - see below. | +| 6-7 | `0x03` | Payload Version | Versioning of the payload format - see below. | ## Route Type Values -| Value | Name | Description | -|--------|-------------------------|-------------| -| `0x00` | `ROUTE_TYPE_RESERVED1` | Reserved for future use. | +| Value | Name | Description | +|--------|------------------------|--------------------------------------| +| `0x00` | `ROUTE_TYPE_RESERVED1` | Reserved for future use. | | `0x01` | `ROUTE_TYPE_FLOOD` | Flood routing mode (builds up path). | -| `0x02` | `ROUTE_TYPE_DIRECT` | Direct route (path is supplied). | -| `0x03` | `ROUTE_TYPE_RESERVED2` | Reserved for future use. | +| `0x02` | `ROUTE_TYPE_DIRECT` | Direct route (path is supplied). | +| `0x03` | `ROUTE_TYPE_RESERVED2` | Reserved for future use. | ## Payload Type Values -| Value | Name | Description | -|--------|-------------------------|-------------| -| `0x00` | `PAYLOAD_TYPE_REQ` | Request (destination/source hashes + MAC). | -| `0x01` | `PAYLOAD_TYPE_RESPONSE` | Response to REQ or ANON_REQ. | -| `0x02` | `PAYLOAD_TYPE_TXT_MSG` | Plain text message. | -| `0x03` | `PAYLOAD_TYPE_ACK` | Acknowledgment. | -| `0x04` | `PAYLOAD_TYPE_ADVERT` | Node advertisement. | -| `0x05` | `PAYLOAD_TYPE_GRP_TXT` | Group text message (unverified). | -| `0x06` | `PAYLOAD_TYPE_GRP_DATA` | Group datagram (unverified). | -| `0x07` | `PAYLOAD_TYPE_ANON_REQ` | Anonymous request. | -| `0x08` | `PAYLOAD_TYPE_PATH` | Returned path. | +| Value | Name | Description | +|--------|---------------------------|-----------------------------------------------| +| `0x00` | `PAYLOAD_TYPE_REQ` | Request (destination/source hashes + MAC). | +| `0x01` | `PAYLOAD_TYPE_RESPONSE` | Response to REQ or ANON_REQ. | +| `0x02` | `PAYLOAD_TYPE_TXT_MSG` | Plain text message. | +| `0x03` | `PAYLOAD_TYPE_ACK` | Acknowledgment. | +| `0x04` | `PAYLOAD_TYPE_ADVERT` | Node advertisement. | +| `0x05` | `PAYLOAD_TYPE_GRP_TXT` | Group text message (unverified). | +| `0x06` | `PAYLOAD_TYPE_GRP_DATA` | Group datagram (unverified). | +| `0x07` | `PAYLOAD_TYPE_ANON_REQ` | Anonymous request. | +| `0x08` | `PAYLOAD_TYPE_PATH` | Returned path. | | `0x0F` | `PAYLOAD_TYPE_RAW_CUSTOM` | Custom packet (raw bytes, custom encryption). | ## Payload Version Values -| Value | Name | Description | -|--------|---------------|-------------| -| `0x00` | `PAYLOAD_VER_1` | 1-byte src/dest hashes, 2-byte MAC. | -| `0x01` | `PAYLOAD_VER_2` | Future version (e.g., 2-byte hashes, 4-byte MAC). | -| `0x02` | `PAYLOAD_VER_3` | Future version. | -| `0x03` | `PAYLOAD_VER_4` | Future version. | +| Value | Version | Description | +|--------|---------|---------------------------------------------------| +| `0x00` | 1 | 1-byte src/dest hashes, 2-byte MAC. | +| `0x01` | 2 | Future version (e.g., 2-byte hashes, 4-byte MAC). | +| `0x02` | 3 | Future version. | +| `0x03` | 4 | Future version. | From 7fffe7755acdab83b779e133051ad3ec3d25e699 Mon Sep 17 00:00:00 2001 From: uncle lit <43320854+LitBomb@users.noreply.github.com> Date: Fri, 13 Jun 2025 13:36:00 -0700 Subject: [PATCH 03/39] Update faq.md add full erase instructions using flasher.meshcore.co.uk add nRF fault tolerant bootloader by discord@che aporeps --- docs/faq.md | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index c61c8d2b..7a5e28ac 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -64,9 +64,11 @@ author: https://github.com/LitBomb - [6.3. Q: How to connect to a repeater via BLE (Bluetooth)?](#63-q-how-to-connect-to-a-repeater-via-ble-bluetooth) - [6.4. Q: I can't connect via Bluetooth, what is the Bluetooth pairing code?](#64-q-i-cant-connect-via-bluetooth-what-is-the-bluetooth-pairing-code) - [6.5. Q: My Heltec V3 keeps disconnecting from my smartphone. It can't hold a solid Bluetooth connection.](#65-q-my-heltec-v3-keeps-disconnecting-from-my-smartphone--it-cant-hold-a-solid-bluetooth-connection) + - [6.6. Q: My RAK/T1000-E/xiao\_nRF52 device seems to be corrupted, how do I wipe it clean to start fresh?](#66-q-my-rakt1000-exiao_nrf52-device-seems-to-be-corrupted-how-do-i-wipe-it-clean-to-start-fresh) - [7. Other Questions:](#7-other-questions) - [7.2 Q: How to update ESP32-based devices over the air?](#72-q-how-to-update-esp32-based-devices-over-the-air) - [7.1 Q: How to update nRF (RAK, T114, Seed XIAO) repeater and room server firmware over the air using the new simpler DFU app?](#71-q-how-to-update-nrf-rak-t114-seed-xiao-repeater-and-room-server-firmware-over-the-air-using-the-new-simpler-dfu-app) + - [7.2 Q: Is there a way to lower the chance of a failed OTA device firmware update (DFU)?](#72-q-is-there-a-way-to-lower-the-chance-of-a-failed-ota-device-firmware-update-dfu) ## 1. Introduction @@ -533,6 +535,27 @@ You can get the epoch time on and use it to se **A:** Heltec V3 has a very small coil antenna on its PCB for Wi-Fi and Bluetooth connectivity. It has a very short range, only a few feet. It is possible to remove the coil antenna and replace it with a 31mm wire. The BT range is much improved with the modification. +### 6.6. Q: My RAK/T1000-E/xiao_nRF52 device seems to be corrupted, how do I wipe it clean to start fresh? + +**A:** +1. Connect USB-C cable to your device, per your device's instruction, get it to flash mode: + - For RAK, double click its reset button + - For T1000-e, quickly disconnect and reconnect the magnetic side of the cable from the device TWICE + - For Heltec T114, click the reset button once (the bottom button) + - For Xiao nRF52, click the reset button once. If that doesn't work, quickly double click the reset button twice. If that doesn't work, disconnection the board from your PC and reconnect again ([seeed studio wiki](https://wiki.seeedstudio.com/XIAO_BLE/#access-the-swd-pins-for-debugging-and-reflashing-bootloader)) +5. A new folder will appear on your computer's desktop +6. Download the `flash_erase*.uf2` file for your device on flasher.meshcore.co.uk + - RAK WisBlock and Heltec T114: `Flash_erase-nRF32_softdevice_v6.uf2` + - Seeed Studio Xiao nRF52 WIO: `Flash_erase-nRF52_softdevice_v7.uf2` +8. drag and drop the uf2 file for your device to the root of the new folder +9. Wait for the copy to complete. You might get an error dialog, you can ignore it +10. Go to https://flasher.meshcore.co.uk/, click `Console` and select the serial port for your connected device +11. In the console, press enter. Your flash should now be erased +12. You may now flash the latest MeshCore firmware onto your device + +Separately, starting in firmware version 1.7.0, there is a CLI Rescue mode. If your device has a user button (e.g. some RAK, T114), you can activate the rescue mode by hold down the user button of the device within 8 seconds of boot. Then you can use the 'Console' on flasher.meshcore.co.uk + + --- ## 7. Other Questions: @@ -558,12 +581,25 @@ You can get the epoch time on and use it to se 4. Go to the Command Line tab, type `start ota` and hit enter. 5. you should see `OK` to confirm the repeater device is now in OTA mode 6. Run the DFU app,tab `Settings` on the top right corner -7. Enable `Packets receipt notifications` and change `Number of Packets` to 10 for RAK, 8 for T114. 8 also works for RAK. -8. Select the firmware zip file you downloaded -9. Select the device you want to update. If the device you want to updat is not on the list, try enabling`OTA` on the device again -10. Tab the `Upload` to begin OTA update -11. If it fails, try turning off and on Bluetooth on your phone. If that doesn't work, try rebooting your phone. -12. Wait for the update to complete. It can take a few minutes. +7. Enable `Packets receipt notifications`, and change `Number of Packets` to 10 for RAK, 8 for T114. 8 also works for RAK. +9. Select the firmware zip file you downloaded +10. Select the device you want to update. If the device you want to updat is not on the list, try enabling`OTA` on the device again +11. If the device is not found, enable `Force Scanning` in the DFU app +12. Tab the `Upload` to begin OTA update +13. If it fails, try turning off and on Bluetooth on your phone. If that doesn't work, try rebooting your phone. +14. Wait for the update to complete. It can take a few minutes. + +### 7.2 Q: Is there a way to lower the chance of a failed OTA device firmware update (DFU)? + +**A:** Yes, developer `che aporeps` has an enhanced OTA DFU bootloader for nRF52 based devices. With this bootloader, if it detects that the application firmware is invalid, it falls back to OTA DFU mode so you can attempt to flash again to recover. This bootloader has other changes to make the OTA DFU process more fault tolerant. + +Refer to https://github.com/oltaco/Adafruit_nRF52_Bootloader_OTAFIX for the latest information. + +Currently, the following boards are supported: +- Nologo ProMicro +- Seeed Studio XIAO nRF52840 BLE +- Seeed Studio XIAO nRF52840 BLE SENSE +- RAK 4631 --- From f4463154cff38e0f9718f8ee1f247e4911bec0f0 Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Fri, 20 Jun 2025 14:20:42 -0700 Subject: [PATCH 04/39] allows manual BLE pin even when device has display also updates remaining variants to use default of 123456 instead of 0 for random pin --- examples/companion_radio/MyMesh.cpp | 4 ++-- variants/heltec_v2/platformio.ini | 2 +- variants/heltec_v3/platformio.ini | 2 +- variants/nano_g2_ultra/platformio.ini | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 034f0206..da7150a1 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -613,10 +613,10 @@ void MyMesh::begin(bool has_display) { _prefs.cr = constrain(_prefs.cr, 5, 8); _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER); -#ifdef BLE_PIN_CODE +#ifdef BLE_PIN_CODE // 123456 by default if (_prefs.ble_pin == 0) { #ifdef DISPLAY_CLASS - if (has_display) { + if (has_display && BLE_PIN_CODE == 123456) { StdRNG rng; _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session } else { diff --git a/variants/heltec_v2/platformio.ini b/variants/heltec_v2/platformio.ini index 562b309d..43bc43ad 100644 --- a/variants/heltec_v2/platformio.ini +++ b/variants/heltec_v2/platformio.ini @@ -96,7 +96,7 @@ build_flags = -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 - -D BLE_PIN_CODE=0 + -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 ; -D MESH_PACKET_LOGGING=1 diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index e8818fdd..41015477 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -107,7 +107,7 @@ build_flags = -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=SSD1306Display - -D BLE_PIN_CODE=0 ; dynamic, random PIN + -D BLE_PIN_CODE=123456 ; dynamic, random PIN -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 ; -D MESH_PACKET_LOGGING=1 diff --git a/variants/nano_g2_ultra/platformio.ini b/variants/nano_g2_ultra/platformio.ini index 20928bdf..c2bb1f23 100644 --- a/variants/nano_g2_ultra/platformio.ini +++ b/variants/nano_g2_ultra/platformio.ini @@ -36,7 +36,7 @@ build_flags = -I src/helpers/ui -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 - -D BLE_PIN_CODE=0 + -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -D DISPLAY_CLASS=SH1106Display From 0d78df1b8a2f45048e3398a752b860426fb3787b Mon Sep 17 00:00:00 2001 From: Matthew Sainsbury Date: Fri, 20 Jun 2025 17:59:55 -0700 Subject: [PATCH 05/39] minor changes and fixes to docs --- docs/packet_structure.md | 19 ++++++++++-------- docs/payloads.md | 42 ++++++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/docs/packet_structure.md b/docs/packet_structure.md index b02c3c33..4a28526f 100644 --- a/docs/packet_structure.md +++ b/docs/packet_structure.md @@ -11,20 +11,22 @@ Note: see the [payloads doc](./payloads.md) for more information about the conte ## Header Breakdown +bit 0 means the lowest bit (1s place) + | Bits | Mask | Field | Description | |-------|--------|-----------------|-----------------------------------------------| | 0-1 | `0x03` | Route Type | Flood, Direct, Reserved - see below. | -| 2-5 | `0x0F` | Payload Type | Request, Response, ACK, etc. - see below. | -| 6-7 | `0x03` | Payload Version | Versioning of the payload format - see below. | +| 2-5 | `0x3C` | Payload Type | Request, Response, ACK, etc. - see below. | +| 6-7 | `0xC0` | Payload Version | Versioning of the payload format - see below. | ## Route Type Values -| Value | Name | Description | -|--------|------------------------|--------------------------------------| -| `0x00` | `ROUTE_TYPE_RESERVED1` | Reserved for future use. | -| `0x01` | `ROUTE_TYPE_FLOOD` | Flood routing mode (builds up path). | -| `0x02` | `ROUTE_TYPE_DIRECT` | Direct route (path is supplied). | -| `0x03` | `ROUTE_TYPE_RESERVED2` | Reserved for future use. | +| Value | Name | Description | +|--------|-------------------------------|--------------------------------------| +| `0x00` | `ROUTE_TYPE_TRANSPORT_FLOOD` | Flood routing mode + transport codes | +| `0x01` | `ROUTE_TYPE_FLOOD` | Flood routing mode (builds up path). | +| `0x02` | `ROUTE_TYPE_DIRECT` | Direct route (path is supplied). | +| `0x03` | `ROUTE_TYPE_TRANSPORT_DIRECT` | direct route + transport codes | ## Payload Type Values @@ -39,6 +41,7 @@ Note: see the [payloads doc](./payloads.md) for more information about the conte | `0x06` | `PAYLOAD_TYPE_GRP_DATA` | Group datagram (unverified). | | `0x07` | `PAYLOAD_TYPE_ANON_REQ` | Anonymous request. | | `0x08` | `PAYLOAD_TYPE_PATH` | Returned path. | +| `0x09` | `PAYLOAD_TYPE_TRACE` | trace a path, collecting SNI for each hop. | | `0x0F` | `PAYLOAD_TYPE_RAW_CUSTOM` | Custom packet (raw bytes, custom encryption). | ## Payload Version Values diff --git a/docs/payloads.md b/docs/payloads.md index 2c402102..72ce0a89 100644 --- a/docs/payloads.md +++ b/docs/payloads.md @@ -1,25 +1,29 @@ # Meshcore payloads Inside of each [meshcore packet](./packet_structure.md) is a payload, identified by the payload type in the packet header. The types of payloads are: +* Node advertisement. +* Acknowledgment. +* Returned path. * Request (destination/source hashes + MAC). * Response to REQ or ANON_REQ. * Plain text message. -* Acknowledgment. -* Node advertisement. +* Anonymous request. * Group text message (unverified). * Group datagram (unverified). -* Anonymous request. -* Returned path. * Custom packet (raw bytes, custom encryption). This document defines the structure of each of these payload types +## Important concepts: + +* Node/channel hash: the first byte of the node or channel's public key + # Node advertisement This kind of payload notifies receivers that a node exists, and gives information about the node | Field | Size (bytes) | Description | |---------------|-----------------|----------------------------------------------------------| -| public key | 32 | Ed25519 public key | +| public key | 32 | Ed25519 public key of the node | | timestamp | 4 | unix timestamp of advertisement | | signature | 64 | Ed25519 signature of public key, timestamp, and app data | | appdata | rest of payload | optional, see below | @@ -45,12 +49,18 @@ Appdata Flags | `0x80` | name | appdata contains a node name | # Acknowledgement + +An acknowledgement that a message was received. Note that for returned path messages, an acknowledgement will be sent in the "extra" payload (see [Returned Path](#returned-path)) and not as a discrete ackowledgement. CLI commands do not require an acknowledgement, neither discrete nor extra. + | Field | Size (bytes) | Description | |----------|--------------|------------------------------------------------------------| | checksum | 4 | CRC checksum of message timestamp, text, and sender pubkey | # Returned path, request, response, and plain text message + +Returned path, request, response, and plain text messages are all formatted in the same way. See the subsection for more details about the ciphertext's associated plaintext representation. + | Field | Size (bytes) | Description | |------------------|-----------------|------------------------------------------------------| | destination hash | 1 | first byte of destination node public key | @@ -60,11 +70,13 @@ Appdata Flags ## Returned path +Returned path messages provide a description of the route a packet took from the original author. Receivers will send returned path messages to the author of the original message. + | Field | Size (bytes) | Description | |-------------|--------------|----------------------------------------------------------------------------------------------| | path length | 1 | length of next field | -| path | see above | a list of node hashes (one byte each) describing the route from us to the packet author | -| extra type | 1 | extra, bundled payload type, eg., acknowledgement or response. See packet structure spec | +| path | see above | a list of node hashes (one byte each) | +| extra type | 1 | extra, bundled payload type, eg., acknowledgement or response. Same values as in [packet structure](./packet_structure.md) | | extra | rest of data | extra, bundled payload content, follows same format as main content defined by this document | ## Request @@ -156,18 +168,14 @@ Plaintext message # Group text message / datagram -| Field | Size (bytes) | Description | -|--------------|-----------------|------------------------------------------| -| channel hash | 1 | TODO | -| cipher MAC | 2 | MAC for encrypted data in next field | -| ciphertext | rest of payload | encrypted message, see below for details | +| Field | Size (bytes) | Description | +|--------------|-----------------|--------------------------------------------| +| channel hash | 1 | the first byte of the channel's public key | +| cipher MAC | 2 | MAC for encrypted data in next field | +| ciphertext | rest of payload | encrypted message, see below for details | -Plaintext for text message +The plaintext contained in the ciphertext matches the format described in [plain text message](#plain-text-message). Specifically, it consists of a four byte timestamp, a flags byte, and the message. The flags byte will generally be `0x00` because it is a "plain text message". The message will be of the form `: ` (eg., `user123: I'm on my way`). -| Field | Size (bytes) | Description | -|-----------|-----------------|----------------------------------| -| timestamp | 4 | send time (unix timestamp) | -| content | rest of message | plain group text message content | TODO: describe what datagram looks like From 1de5753a16dd7aba2a3df3510aef961d5df94676 Mon Sep 17 00:00:00 2001 From: Matthew Sainsbury Date: Fri, 20 Jun 2025 19:41:07 -0700 Subject: [PATCH 06/39] add advert detail --- docs/payloads.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/payloads.md b/docs/payloads.md index 72ce0a89..b094d9a9 100644 --- a/docs/payloads.md +++ b/docs/payloads.md @@ -41,12 +41,15 @@ Appdata Appdata Flags -| Value | Name | Description | -|--------|-----------|---------------------------------------| -| `0x10` | location | appdata contains lat/long information | -| `0x20` | feature 1 | Reserved for future use. | -| `0x40` | feature 2 | Reserved for future use. | -| `0x80` | name | appdata contains a node name | +| Value | Name | Description | +|--------|----------------|---------------------------------------| +| `0x01` | is chat node | advert is for a chat node | +| `0x02` | is repeater | advert is for a repeater | +| `0x03` | is room server | advert is for a room server | +| `0x10` | has location | appdata contains lat/long information | +| `0x20` | has feature 1 | Reserved for future use. | +| `0x40` | has feature 2 | Reserved for future use. | +| `0x80` | has name | appdata contains a node name | # Acknowledgement From 001b996a24ca1cab1254edade2f9391991dfb521 Mon Sep 17 00:00:00 2001 From: cod3doomy Date: Tue, 24 Jun 2025 17:46:01 -0700 Subject: [PATCH 07/39] RAK4631: BME680 add and GPS cleanup - Added the BME680 environment sensor functionality - Added the GPS Repeater env for those wanting it - Cleaned up the GPS and other RAK4631SensorManager code Verified build and functionality on normal and GPS repeater and companion envs. IAQ readout is still a work in progress, but a placeholder can be seen on Channel 2 of the app telemetry. --- variants/rak4631/platformio.ini | 29 +++- variants/rak4631/target.cpp | 266 ++++++++++++++++++++++++++++---- variants/rak4631/target.h | 32 ++-- 3 files changed, 285 insertions(+), 42 deletions(-) diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 3014bc59..9391f99b 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -23,7 +23,6 @@ lib_deps = ${nrf52840_base.lib_deps} adafruit/Adafruit SSD1306 @ ^2.5.13 stevemarple/MicroNMEA @ ^2.0.6 - sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27 [env:RAK_4631_Repeater] extends = rak4631 @@ -41,6 +40,30 @@ build_src_filter = ${rak4631.build_src_filter} + +<../examples/simple_repeater> +[env:RAK_4631_GPS_Repeater] +extends = rak4631 +build_flags = + ${rak4631.build_flags} + -D DISPLAY_CLASS=SSD1306Display + -D ADVERT_NAME='"RAK4631 GPS Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 + -D FORCE_GPS_ALIVE=1 + -D ENV_INCLUDE_GPS=1 + -D ENV_INCLUDE_BME680=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${rak4631.build_src_filter} + + + +<../examples/simple_repeater> +lib_deps = + ${rak4631.lib_deps} + sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27 + https://github.com/boschsensortec/Bosch-BSEC2-Library + https://github.com/boschsensortec/Bosch-BME68x-Library + [env:RAK_4631_room_server] extends = rak4631 build_flags = @@ -104,6 +127,7 @@ build_flags = -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -D ENV_INCLUDE_GPS=1 + -D ENV_INCLUDE_BME680=1 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak4631.build_src_filter} @@ -112,6 +136,9 @@ build_src_filter = ${rak4631.build_src_filter} +<../examples/companion_radio> lib_deps = ${rak4631.lib_deps} + sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27 + https://github.com/boschsensortec/Bosch-BSEC2-Library + https://github.com/boschsensortec/Bosch-BME68x-Library densaugeo/base64 @ ~1.4.0 [env:RAK_4631_terminal_chat] diff --git a/variants/rak4631/target.cpp b/variants/rak4631/target.cpp index ede755e2..b7c74bf4 100644 --- a/variants/rak4631/target.cpp +++ b/variants/rak4631/target.cpp @@ -19,6 +19,21 @@ RAK4631SensorManager sensors = RAK4631SensorManager(nmea); RAK4631SensorManager sensors; #endif +#if ENV_INCLUDE_BME680 +#ifndef TELEM_BME680_ADDRESS +#define TELEM_BME680_ADDRESS 0x76 // BME680 environmental sensor I2C address +#endif +#include +static Bsec2 BME680; +float rawPressure = 0; +float rawTemperature = 0; +float compTemperature = 0; +float rawHumidity = 0; +float compHumidity = 0; +float readIAQ = 0; +float readCO2 = 0; +#endif + #ifdef DISPLAY_CLASS DISPLAY_CLASS display; #endif @@ -43,6 +58,10 @@ void scanDevices(TwoWire *w) Serial.println("\tFound RAK12500 GPS Sensor"); deviceOnline |= RAK12500_ONLINE; break; + case 0x76: + Serial.println("\tFound RAK1906 Environment Sensor"); + deviceOnline |= BME680_ONLINE; + break; default: Serial.print("\tI2C device found at address 0x"); if (addr < 16) { @@ -137,7 +156,7 @@ bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){ ublox_GNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); disStandbyPin = ioPin; gps_active = true; - gps_present = true; + gps_detected = true; return true; } else @@ -147,73 +166,256 @@ bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){ } #endif +#if ENV_INCLUDE_BME680 +void checkBMEStatus(Bsec2 bsec) +{ + if (bsec.status < BSEC_OK) + { + MESH_DEBUG_PRINTLN("BSEC error code : %f", String(bsec.status)); + } + else if (bsec.status > BSEC_OK) + { + MESH_DEBUG_PRINTLN("BSEC warning code : %f", String(bsec.status)); + } + + if (bsec.sensor.status < BME68X_OK) + { + MESH_DEBUG_PRINTLN("BME68X error code : %f", String(bsec.sensor.status)); + } + else if (bsec.sensor.status > BME68X_OK) + { + MESH_DEBUG_PRINTLN("BME68X warning code : %f", String(bsec.sensor.status)); + } +} +void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec) +{ + if (!outputs.nOutputs) + { + MESH_DEBUG_PRINTLN("No new data to report out"); + return; + } + + MESH_DEBUG_PRINTLN("BSEC outputs:\n\tTime stamp = %f", String((int) (outputs.output[0].time_stamp / INT64_C(1000000)))); + for (uint8_t i = 0; i < outputs.nOutputs; i++) + { + const bsecData output = outputs.output[i]; + switch (output.sensor_id) + { + case BSEC_OUTPUT_IAQ: + MESH_DEBUG_PRINTLN("\tIAQ = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tIAQ accuracy = %f", String((int) output.accuracy)); + break; + case BSEC_OUTPUT_RAW_TEMPERATURE: + rawTemperature = output.signal; + MESH_DEBUG_PRINTLN("\tTemperature = %f", String(output.signal)); + break; + case BSEC_OUTPUT_RAW_PRESSURE: + rawPressure = output.signal; + MESH_DEBUG_PRINTLN("\tPressure = %f", String(output.signal)); + break; + case BSEC_OUTPUT_RAW_HUMIDITY: + rawHumidity = output.signal; + MESH_DEBUG_PRINTLN("\tHumidity = %f", String(output.signal)); + break; + case BSEC_OUTPUT_RAW_GAS: + MESH_DEBUG_PRINTLN("\tGas resistance = %f", String(output.signal)); + break; + case BSEC_OUTPUT_STABILIZATION_STATUS: + MESH_DEBUG_PRINTLN("\tStabilization status = %f", String(output.signal)); + break; + case BSEC_OUTPUT_RUN_IN_STATUS: + MESH_DEBUG_PRINTLN("\tRun in status = %f", String(output.signal)); + break; + case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: + compTemperature = output.signal; + MESH_DEBUG_PRINTLN("\tCompensated temperature = %f", String(output.signal)); + break; + case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: + compHumidity = output.signal; + MESH_DEBUG_PRINTLN("\tCompensated humidity = %f", String(output.signal)); + break; + case BSEC_OUTPUT_STATIC_IAQ: + readIAQ = output.signal; + MESH_DEBUG_PRINTLN("\tStatic IAQ = %f", String(output.signal)); + break; + case BSEC_OUTPUT_CO2_EQUIVALENT: + readCO2 = output.signal; + MESH_DEBUG_PRINTLN("\tCO2 Equivalent = %f", String(output.signal)); + break; + case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT: + MESH_DEBUG_PRINTLN("\tbVOC equivalent = %f", String(output.signal)); + break; + case BSEC_OUTPUT_GAS_PERCENTAGE: + MESH_DEBUG_PRINTLN("\tGas percentage = %f", String(output.signal)); + break; + case BSEC_OUTPUT_COMPENSATED_GAS: + MESH_DEBUG_PRINTLN("\tCompensated gas = %f", String(output.signal)); + break; + default: + break; + } + } +} +#endif + bool RAK4631SensorManager::begin() { #ifdef MESH_DEBUG scanDevices(&Wire); #endif -#if ENV_INCLUDE_GPS - //search for the correct IO standby pin depending on socket used - if(gpsIsAwake(P_GPS_STANDBY_A)){ - MESH_DEBUG_PRINTLN("GPS is on socket A"); - } - else if(gpsIsAwake(P_GPS_STANDBY_C)){ - MESH_DEBUG_PRINTLN("GPS is on socket C"); - } - else if(gpsIsAwake(P_GPS_STANDBY_F)){ - MESH_DEBUG_PRINTLN("GPS is on socket F"); - } - else{ - MESH_DEBUG_PRINTLN("Error: No GPS found on sockets A, C or F"); - gps_active = false; - gps_present = false; - return false; - } + #if ENV_INCLUDE_GPS + //search for the correct IO standby pin depending on socket used + if(gpsIsAwake(P_GPS_STANDBY_A)){ + MESH_DEBUG_PRINTLN("GPS is on socket A"); + } + else if(gpsIsAwake(P_GPS_STANDBY_C)){ + MESH_DEBUG_PRINTLN("GPS is on socket C"); + } + else if(gpsIsAwake(P_GPS_STANDBY_F)){ + MESH_DEBUG_PRINTLN("GPS is on socket F"); + } + else{ + MESH_DEBUG_PRINTLN("Error: No GPS found on sockets A, C or F"); + gps_active = false; + gps_detected = false; + return false; + } - //Now that GPS is found and set up, set to sleep for initial state - stop_gps(); -#endif + #ifndef FORCE_GPS_ALIVE + //Now that GPS is found and set up, set to sleep for initial state + stop_gps(); + #endif + #endif + + #if ENV_INCLUDE_BME680 + + bsecSensor sensorList[4] = { + BSEC_OUTPUT_IAQ, + // BSEC_OUTPUT_RAW_TEMPERATURE, + BSEC_OUTPUT_RAW_PRESSURE, + // BSEC_OUTPUT_RAW_HUMIDITY, + // BSEC_OUTPUT_RAW_GAS, + // BSEC_OUTPUT_STABILIZATION_STATUS, + // BSEC_OUTPUT_RUN_IN_STATUS, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, + // BSEC_OUTPUT_STATIC_IAQ, + // BSEC_OUTPUT_CO2_EQUIVALENT, + // BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, + // BSEC_OUTPUT_GAS_PERCENTAGE, + // BSEC_OUTPUT_COMPENSATED_GAS + }; + + if(!BME680.begin(TELEM_BME680_ADDRESS, Wire)){ + checkBMEStatus(BME680); + bme680_present = false; + bme680_active = false; + return false; + } + + MESH_DEBUG_PRINTLN("Found BME680 at address: %02X", TELEM_BME680_ADDRESS); + bme680_present = true; + bme680_active = true; + + if (SAMPLING_RATE == BSEC_SAMPLE_RATE_ULP) + { + BME680.setTemperatureOffset(BSEC_SAMPLE_RATE_ULP); + } + else if (SAMPLING_RATE == BSEC_SAMPLE_RATE_LP) + { + BME680.setTemperatureOffset(TEMP_OFFSET_LP); + } + + if (!BME680.updateSubscription(sensorList, ARRAY_LEN(sensorList), SAMPLING_RATE)) + { + checkBMEStatus(BME680); + } + + BME680.attachCallback(newDataCallback); + + #endif } -#if ENV_INCLUDE_GPS bool RAK4631SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + #ifdef ENV_INCLUDE_GPS if (requester_permissions & TELEM_PERM_LOCATION && gps_active) { // does requester have permission? telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); } + #endif + + if (requester_permissions & TELEM_PERM_ENVIRONMENT) { + + #if ENV_INCLUDE_BME680 + if (bme680_active) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, compTemperature); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, compHumidity); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, rawPressure); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF+1, readIAQ); + } + #endif + } return true; } void RAK4631SensorManager::loop() { static long next_update = 0; + #ifdef ENV_INCLUDE_GPS _nmea->loop(); + #endif - if (millis() > next_update && gps_active) { - node_lat = (double)ublox_GNSS.getLatitude()/10000000.; - node_lon = (double)ublox_GNSS.getLongitude()/10000000.; - node_altitude = (double)ublox_GNSS.getAltitude()/1000.; - MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude); + if (millis() > next_update) { + #ifdef ENV_INCLUDE_GPS + if(gps_active){ + node_lat = (double)ublox_GNSS.getLatitude()/10000000.; + node_lon = (double)ublox_GNSS.getLongitude()/10000000.; + node_altitude = (double)ublox_GNSS.getAltitude()/1000.; + MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude); + } + #endif + + #ifdef ENV_INCLUDE_BME680 + if(bme680_active){ + if (!BME680.run()){ + checkBMEStatus(BME680); + } + } + #endif next_update = millis() + 1000; } + } -int RAK4631SensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) +int RAK4631SensorManager::getNumSettings() const { + #if ENV_INCLUDE_GPS + return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected + #else + return 0; + #endif +} const char* RAK4631SensorManager::getSettingName(int i) const { - return i == 0 ? "gps" : NULL; + #if ENV_INCLUDE_GPS + return (gps_detected && i == 0) ? "gps" : NULL; + #else + return NULL; + #endif } const char* RAK4631SensorManager::getSettingValue(int i) const { - if (i == 0) { + #if ENV_INCLUDE_GPS + if (gps_detected && i == 0) { return gps_active ? "1" : "0"; } + #endif return NULL; } bool RAK4631SensorManager::setSettingValue(const char* name, const char* value) { - if (strcmp(name, "gps") == 0) { + #if ENV_INCLUDE_GPS + if (gps_detected && strcmp(name, "gps") == 0) { if (strcmp(value, "0") == 0) { stop_gps(); } else { @@ -221,9 +423,9 @@ bool RAK4631SensorManager::setSettingValue(const char* name, const char* value) } return true; } + #endif return false; // not supported } -#endif mesh::LocalIdentity radio_new_identity() { RadioNoiseListener rng(radio); diff --git a/variants/rak4631/target.h b/variants/rak4631/target.h index 3e6db0aa..0460c9e8 100644 --- a/variants/rak4631/target.h +++ b/variants/rak4631/target.h @@ -11,6 +11,9 @@ #include #include #endif +#if ENV_INCLUDE_BME680 + #include "bsec2.h" +#endif #ifdef DISPLAY_CLASS #include #endif @@ -20,7 +23,7 @@ class RAK4631SensorManager: public SensorManager { #if ENV_INCLUDE_GPS bool gps_active = false; - bool gps_present = false; + bool gps_detected = false; LocationProvider * _nmea; SFE_UBLOX_GNSS ublox_GNSS; uint32_t disStandbyPin = 0; @@ -32,20 +35,26 @@ class RAK4631SensorManager: public SensorManager { bool gpsIsAwake(uint32_t ioPin); #endif + #if ENV_INCLUDE_BME680 + bool bme680_active = false; + bool bme680_present = false; + #define SAMPLING_RATE BSEC_SAMPLE_RATE_ULP + #endif + public: #if ENV_INCLUDE_GPS RAK4631SensorManager(LocationProvider &nmea): _nmea(&nmea) { } - - 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; #else RAK4631SensorManager() { } #endif - bool begin() override; + + void loop() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) 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; + bool begin() override; }; extern RAK4631Board board; @@ -75,6 +84,11 @@ enum { RAK12500_ONLINE = _BV(14), }; +#if ENV_INCLUDE_BME680 + void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec); + void checkBMEStatus(Bsec2 bsec); +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); From 669ff39cd6b7c37cf5c8a03b81698ec49763349a Mon Sep 17 00:00:00 2001 From: "Ricardo F." <112904881+rfmoz@users.noreply.github.com> Date: Wed, 25 Jun 2025 22:41:14 +0200 Subject: [PATCH 08/39] Update faq.md Order last other questions and add fix to WebFlasher from linux --- docs/faq.md | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 7a5e28ac..1c67c9c7 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -65,10 +65,12 @@ author: https://github.com/LitBomb - [6.4. Q: I can't connect via Bluetooth, what is the Bluetooth pairing code?](#64-q-i-cant-connect-via-bluetooth-what-is-the-bluetooth-pairing-code) - [6.5. Q: My Heltec V3 keeps disconnecting from my smartphone. It can't hold a solid Bluetooth connection.](#65-q-my-heltec-v3-keeps-disconnecting-from-my-smartphone--it-cant-hold-a-solid-bluetooth-connection) - [6.6. Q: My RAK/T1000-E/xiao\_nRF52 device seems to be corrupted, how do I wipe it clean to start fresh?](#66-q-my-rakt1000-exiao_nrf52-device-seems-to-be-corrupted-how-do-i-wipe-it-clean-to-start-fresh) + - [6.7. Q: WebFlasher fails on Linux with failed to open](#67-q-webflasher-fails-on-Linux-with-failed-to-open) + - [7. Other Questions:](#7-other-questions) - - [7.2 Q: How to update ESP32-based devices over the air?](#72-q-how-to-update-esp32-based-devices-over-the-air) - [7.1 Q: How to update nRF (RAK, T114, Seed XIAO) repeater and room server firmware over the air using the new simpler DFU app?](#71-q-how-to-update-nrf-rak-t114-seed-xiao-repeater-and-room-server-firmware-over-the-air-using-the-new-simpler-dfu-app) - - [7.2 Q: Is there a way to lower the chance of a failed OTA device firmware update (DFU)?](#72-q-is-there-a-way-to-lower-the-chance-of-a-failed-ota-device-firmware-update-dfu) + - [7.2 Q: How to update ESP32-based devices over the air?](#72-q-how-to-update-esp32-based-devices-over-the-air) + - [7.3 Q: Is there a way to lower the chance of a failed OTA device firmware update (DFU)?](#73-q-is-there-a-way-to-lower-the-chance-of-a-failed-ota-device-firmware-update-dfu) ## 1. Introduction @@ -556,21 +558,17 @@ You can get the epoch time on and use it to se Separately, starting in firmware version 1.7.0, there is a CLI Rescue mode. If your device has a user button (e.g. some RAK, T114), you can activate the rescue mode by hold down the user button of the device within 8 seconds of boot. Then you can use the 'Console' on flasher.meshcore.co.uk +### 6.7. Q: WebFlasher fails on Linux with failed to open + +**A:** If the usb port doesn't have the right ownership for this task, the process fails with the following error: +`NetworkError: Failed to execute 'open' on 'SerialPort': Failed to open serial port.` + +Allow the browser user on it: +`# setfacl -m u:YOUR_USER_HERE:rw /dev/ttyUSB0` + --- ## 7. Other Questions: -### 7.2 Q: How to update ESP32-based devices over the air? - -**A:** For ESP32-based devices (e.g. Heltec V3): -1. On flasher.meshcore.co.uk, download the **non-merged** version of the firmware for your ESP32 device (e.g. `Heltec_v3_repeater-v1.6.2-4449fd3.bin`, no `"merged"` in the file name) -2. From the MeshCore app, login remotely to the repeater you want to update with admin priviledge -4. Go to the Command Line tab, type `start ota` and hit enter. -5. you should see `OK` to confirm the repeater device is now in OTA mode -6. The command `start ota` on an ESP32-based device starts a wifi hotspot named `MeshCore OTA` -7. From your phone or computer connect to the 'MeshCore OTA' hotspot -8. From a browser, go to http://192.168.4.1/update and upload the non-merged bin from the flasher - - ### 7.1 Q: How to update nRF (RAK, T114, Seed XIAO) repeater and room server firmware over the air using the new simpler DFU app? **A:** The steps below work on both Android and iOS as nRF has made both apps' user interface the same on both platforms: @@ -589,7 +587,20 @@ Separately, starting in firmware version 1.7.0, there is a CLI Rescue mode. If 13. If it fails, try turning off and on Bluetooth on your phone. If that doesn't work, try rebooting your phone. 14. Wait for the update to complete. It can take a few minutes. -### 7.2 Q: Is there a way to lower the chance of a failed OTA device firmware update (DFU)? + +### 7.2 Q: How to update ESP32-based devices over the air? + +**A:** For ESP32-based devices (e.g. Heltec V3): +1. On flasher.meshcore.co.uk, download the **non-merged** version of the firmware for your ESP32 device (e.g. `Heltec_v3_repeater-v1.6.2-4449fd3.bin`, no `"merged"` in the file name) +2. From the MeshCore app, login remotely to the repeater you want to update with admin priviledge +4. Go to the Command Line tab, type `start ota` and hit enter. +5. you should see `OK` to confirm the repeater device is now in OTA mode +6. The command `start ota` on an ESP32-based device starts a wifi hotspot named `MeshCore OTA` +7. From your phone or computer connect to the 'MeshCore OTA' hotspot +8. From a browser, go to http://192.168.4.1/update and upload the non-merged bin from the flasher + + +### 7.3 Q: Is there a way to lower the chance of a failed OTA device firmware update (DFU)? **A:** Yes, developer `che aporeps` has an enhanced OTA DFU bootloader for nRF52 based devices. With this bootloader, if it detects that the application firmware is invalid, it falls back to OTA DFU mode so you can attempt to flash again to recover. This bootloader has other changes to make the OTA DFU process more fault tolerant. @@ -602,4 +613,6 @@ Currently, the following boards are supported: - RAK 4631 + + --- From 63247667d0b5066771dfa293df1501def1e82ad4 Mon Sep 17 00:00:00 2001 From: cod3doomy Date: Wed, 25 Jun 2025 21:12:36 -0700 Subject: [PATCH 09/39] String removed Removed all string type casting --- variants/rak4631/target.cpp | 51 ++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/variants/rak4631/target.cpp b/variants/rak4631/target.cpp index b7c74bf4..45d10975 100644 --- a/variants/rak4631/target.cpp +++ b/variants/rak4631/target.cpp @@ -31,6 +31,7 @@ float compTemperature = 0; float rawHumidity = 0; float compHumidity = 0; float readIAQ = 0; +float readStaticIAQ = 0; float readCO2 = 0; #endif @@ -171,20 +172,20 @@ void checkBMEStatus(Bsec2 bsec) { if (bsec.status < BSEC_OK) { - MESH_DEBUG_PRINTLN("BSEC error code : %f", String(bsec.status)); + MESH_DEBUG_PRINTLN("BSEC error code : %f", float(bsec.status)); } else if (bsec.status > BSEC_OK) { - MESH_DEBUG_PRINTLN("BSEC warning code : %f", String(bsec.status)); + MESH_DEBUG_PRINTLN("BSEC warning code : %f", float(bsec.status)); } if (bsec.sensor.status < BME68X_OK) { - MESH_DEBUG_PRINTLN("BME68X error code : %f", String(bsec.sensor.status)); + MESH_DEBUG_PRINTLN("BME68X error code : %f", bsec.sensor.status); } else if (bsec.sensor.status > BME68X_OK) { - MESH_DEBUG_PRINTLN("BME68X warning code : %f", String(bsec.sensor.status)); + MESH_DEBUG_PRINTLN("BME68X warning code : %f", bsec.sensor.status); } } void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec) @@ -195,61 +196,62 @@ void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bse return; } - MESH_DEBUG_PRINTLN("BSEC outputs:\n\tTime stamp = %f", String((int) (outputs.output[0].time_stamp / INT64_C(1000000)))); + MESH_DEBUG_PRINTLN("BSEC outputs:\n\tTime stamp = %f", (int) (outputs.output[0].time_stamp / INT64_C(1000000))); for (uint8_t i = 0; i < outputs.nOutputs; i++) { const bsecData output = outputs.output[i]; switch (output.sensor_id) { case BSEC_OUTPUT_IAQ: - MESH_DEBUG_PRINTLN("\tIAQ = %f", String(output.signal)); - MESH_DEBUG_PRINTLN("\tIAQ accuracy = %f", String((int) output.accuracy)); + readIAQ = output.signal; + MESH_DEBUG_PRINTLN("\tIAQ = %f", output.signal); + MESH_DEBUG_PRINTLN("\tIAQ accuracy = %f", output.accuracy); break; case BSEC_OUTPUT_RAW_TEMPERATURE: rawTemperature = output.signal; - MESH_DEBUG_PRINTLN("\tTemperature = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tTemperature = %f", output.signal); break; case BSEC_OUTPUT_RAW_PRESSURE: rawPressure = output.signal; - MESH_DEBUG_PRINTLN("\tPressure = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tPressure = %f", output.signal); break; case BSEC_OUTPUT_RAW_HUMIDITY: rawHumidity = output.signal; - MESH_DEBUG_PRINTLN("\tHumidity = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tHumidity = %f", output.signal); break; case BSEC_OUTPUT_RAW_GAS: - MESH_DEBUG_PRINTLN("\tGas resistance = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tGas resistance = %f", output.signal); break; case BSEC_OUTPUT_STABILIZATION_STATUS: - MESH_DEBUG_PRINTLN("\tStabilization status = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tStabilization status = %f", output.signal); break; case BSEC_OUTPUT_RUN_IN_STATUS: - MESH_DEBUG_PRINTLN("\tRun in status = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tRun in status = %f", output.signal); break; case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: compTemperature = output.signal; - MESH_DEBUG_PRINTLN("\tCompensated temperature = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tCompensated temperature = %f", output.signal); break; case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: compHumidity = output.signal; - MESH_DEBUG_PRINTLN("\tCompensated humidity = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tCompensated humidity = %f", output.signal); break; case BSEC_OUTPUT_STATIC_IAQ: - readIAQ = output.signal; - MESH_DEBUG_PRINTLN("\tStatic IAQ = %f", String(output.signal)); + readStaticIAQ = output.signal; + MESH_DEBUG_PRINTLN("\tStatic IAQ = %f", output.signal); break; case BSEC_OUTPUT_CO2_EQUIVALENT: readCO2 = output.signal; - MESH_DEBUG_PRINTLN("\tCO2 Equivalent = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tCO2 Equivalent = %f", output.signal); break; case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT: - MESH_DEBUG_PRINTLN("\tbVOC equivalent = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tbVOC equivalent = %f", output.signal); break; case BSEC_OUTPUT_GAS_PERCENTAGE: - MESH_DEBUG_PRINTLN("\tGas percentage = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tGas percentage = %f", output.signal); break; case BSEC_OUTPUT_COMPENSATED_GAS: - MESH_DEBUG_PRINTLN("\tCompensated gas = %f", String(output.signal)); + MESH_DEBUG_PRINTLN("\tCompensated gas = %f", output.signal); break; default: break; @@ -290,7 +292,7 @@ bool RAK4631SensorManager::begin() { #if ENV_INCLUDE_BME680 - bsecSensor sensorList[4] = { + bsecSensor sensorList[5] = { BSEC_OUTPUT_IAQ, // BSEC_OUTPUT_RAW_TEMPERATURE, BSEC_OUTPUT_RAW_PRESSURE, @@ -300,7 +302,7 @@ bool RAK4631SensorManager::begin() { // BSEC_OUTPUT_RUN_IN_STATUS, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, - // BSEC_OUTPUT_STATIC_IAQ, + BSEC_OUTPUT_STATIC_IAQ, // BSEC_OUTPUT_CO2_EQUIVALENT, // BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, // BSEC_OUTPUT_GAS_PERCENTAGE, @@ -351,7 +353,8 @@ bool RAK4631SensorManager::querySensors(uint8_t requester_permissions, CayenneLP telemetry.addTemperature(TELEM_CHANNEL_SELF, compTemperature); telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, compHumidity); telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, rawPressure); - telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF+1, readIAQ); + telemetry.addTemperature(TELEM_CHANNEL_SELF+1, readIAQ); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF+1, readStaticIAQ); } #endif } From 07f25ccac817b36cf29a0b5cd9f95cd2ae4cb802 Mon Sep 17 00:00:00 2001 From: recrof Date: Fri, 27 Jun 2025 15:12:48 +0200 Subject: [PATCH 10/39] sx1276 boards: migrate to std_init() --- src/helpers/CustomSX1276.h | 59 ++++++++++++++++++++++++-- variants/heltec_v2/target.cpp | 21 ++------- variants/lilygo_t3s3_sx1276/target.cpp | 23 ++-------- variants/lilygo_tlora_v2_1/target.cpp | 23 +++------- variants/lilygo_tlora_v2_1/target.h | 3 +- 5 files changed, 69 insertions(+), 60 deletions(-) diff --git a/src/helpers/CustomSX1276.h b/src/helpers/CustomSX1276.h index 35d879fc..8396fe07 100644 --- a/src/helpers/CustomSX1276.h +++ b/src/helpers/CustomSX1276.h @@ -12,10 +12,63 @@ class CustomSX1276 : public SX1276 { public: CustomSX1276(Module *mod) : SX1276(mod) { } + #ifdef RP2040_PLATFORM + bool std_init(SPIClassRP2040* spi = NULL) + #else + bool std_init(SPIClass* spi = NULL) + #endif + { + #ifdef LORA_CR + uint8_t cr = LORA_CR; + #else + uint8_t cr = 5; + #endif + + #if defined(P_LORA_SCLK) + #ifdef NRF52_PLATFORM + if (spi) { spi->setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); spi->begin(); } + #elif defined(RP2040_PLATFORM) + if (spi) { + spi->setMISO(P_LORA_MISO); + //spi->setCS(P_LORA_NSS); // Setting CS results in freeze + spi->setSCK(P_LORA_SCLK); + spi->setMOSI(P_LORA_MOSI); + spi->begin(); + } + #else + if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + #endif + #endif + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8); + // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + #ifdef SX127X_CURRENT_LIMIT + setCurrentLimit(SX127X_CURRENT_LIMIT); + #endif + + #if defined(SX176X_RXEN) || defined(SX176X_TXEN) + #ifndef SX176X_RXEN + #define SX176X_RXEN RADIOLIB_NC + #endif + #ifndef SX176X_TXEN + #define SX176X_TXEN RADIOLIB_NC + #endif + setRfSwitchPins(SX176X_RXEN, SX176X_TXEN); + #endif + + setCRC(1); + + return true; // success + } + bool isReceiving() { return (getModemStatus() & - (RH_RF95_MODEM_STATUS_SIGNAL_DETECTED - | RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED + (RH_RF95_MODEM_STATUS_SIGNAL_DETECTED + | RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED | RH_RF95_MODEM_STATUS_HEADER_INFO_VALID)) != 0; } @@ -23,7 +76,7 @@ class CustomSX1276 : public SX1276 { // start CAD int16_t state = startChannelScan(); RADIOLIB_ASSERT(state); - + // wait for channel activity detected or timeout unsigned long timeout = millis() + 16; while(!this->mod->hal->digitalRead(this->mod->getIrq()) && millis() < timeout) { diff --git a/variants/heltec_v2/target.cpp b/variants/heltec_v2/target.cpp index a7e9fa67..d4d21dba 100644 --- a/variants/heltec_v2/target.cpp +++ b/variants/heltec_v2/target.cpp @@ -20,31 +20,16 @@ SensorManager sensors; 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) spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + return radio.std_init(&spi); +#else + return radio.std_init(); #endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - -#ifdef SX127X_CURRENT_LIMIT - radio.setCurrentLimit(SX127X_CURRENT_LIMIT); -#endif - - radio.setCRC(1); - - return true; // success } uint32_t radio_get_rng_seed() { diff --git a/variants/lilygo_t3s3_sx1276/target.cpp b/variants/lilygo_t3s3_sx1276/target.cpp index db11433a..b2ee4455 100644 --- a/variants/lilygo_t3s3_sx1276/target.cpp +++ b/variants/lilygo_t3s3_sx1276/target.cpp @@ -20,33 +20,16 @@ SensorManager sensors; 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) spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + return radio.std_init(&spi); +#else + return radio.std_init(); #endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - -#ifdef SX127X_CURRENT_LIMIT - radio.setCurrentLimit(SX127X_CURRENT_LIMIT); -#endif - - radio.setCRC(1); - - radio.setRfSwitchPins(21, 10); - - return true; // success } uint32_t radio_get_rng_seed() { diff --git a/variants/lilygo_tlora_v2_1/target.cpp b/variants/lilygo_tlora_v2_1/target.cpp index 4d513ed9..6f60b979 100644 --- a/variants/lilygo_tlora_v2_1/target.cpp +++ b/variants/lilygo_tlora_v2_1/target.cpp @@ -10,35 +10,22 @@ WRAPPER_CLASS radio_driver(radio, board); ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -SensorManager sensors; +EnvironmentSensorManager sensors; #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) spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - -#ifdef SX127X_CURRENT_LIMIT - radio.setCurrentLimit(SX127X_CURRENT_LIMIT); + return radio.std_init(&spi); +#else + return radio.std_init(); #endif - - radio.setCRC(1); - - return true; // success } uint32_t radio_get_rng_seed() { diff --git a/variants/lilygo_tlora_v2_1/target.h b/variants/lilygo_tlora_v2_1/target.h index edf28eb4..8e48c3e7 100644 --- a/variants/lilygo_tlora_v2_1/target.h +++ b/variants/lilygo_tlora_v2_1/target.h @@ -7,6 +7,7 @@ #include #include #include +#include #ifdef DISPLAY_CLASS #include #endif @@ -14,7 +15,7 @@ extern LilyGoTLoraBoard board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; -extern SensorManager sensors; +extern EnvironmentSensorManager sensors; #ifdef DISPLAY_CLASS extern DISPLAY_CLASS display; From f666b8c8cf4f4fe97e11f20418833f22280d8159 Mon Sep 17 00:00:00 2001 From: recrof Date: Fri, 27 Jun 2025 15:16:37 +0200 Subject: [PATCH 11/39] RadioWrapper::std_init: add missing definitions for rx/tx switching --- variants/lilygo_t3s3_sx1276/platformio.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/variants/lilygo_t3s3_sx1276/platformio.ini b/variants/lilygo_t3s3_sx1276/platformio.ini index 1bcbbbf9..74eced9c 100644 --- a/variants/lilygo_t3s3_sx1276/platformio.ini +++ b/variants/lilygo_t3s3_sx1276/platformio.ini @@ -21,6 +21,8 @@ build_flags = -D RADIO_CLASS=CustomSX1276 -D WRAPPER_CLASS=CustomSX1276Wrapper -D SX127X_CURRENT_LIMIT=120 + -D SX176X_RXEN=21 + -D SX176X_TXEN=10 -D LORA_TX_POWER=20 build_src_filter = ${esp32_base.build_src_filter} +<../variants/lilygo_t3s3_sx1276> From 95e69cf27312763fef72b151a2758756adc19beb Mon Sep 17 00:00:00 2001 From: recrof Date: Fri, 27 Jun 2025 15:17:51 +0200 Subject: [PATCH 12/39] RadioWrapper::std_init: add tbeam, unify coding style --- variants/lilygo_tbeam/target.cpp | 78 ++++++++++++-------------------- 1 file changed, 28 insertions(+), 50 deletions(-) diff --git a/variants/lilygo_tbeam/target.cpp b/variants/lilygo_tbeam/target.cpp index 69a980fc..c482dd04 100644 --- a/variants/lilygo_tbeam/target.cpp +++ b/variants/lilygo_tbeam/target.cpp @@ -4,7 +4,7 @@ TBeamBoard board; // Using PMU AXP2102 -#define PMU_WIRE_PORT Wire +#define PMU_WIRE_PORT Wire bool pmuIntFlag = false; static void setPMUIntFlag(){ @@ -32,47 +32,38 @@ SensorManager sensors; #define LORA_CR 5 #endif -bool TBeamBoard::power_init() -{ - if (!PMU) - { +bool TBeamBoard::power_init() { + if (!PMU) { PMU = new XPowersAXP2101(PMU_WIRE_PORT); - if (!PMU->init()) - { + if (!PMU->init()) { // Serial.println("Warning: Failed to find AXP2101 power management"); delete PMU; PMU = NULL; } - else - { + else { // Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU"); } } - if (!PMU) - { + if (!PMU) { PMU = new XPowersAXP192(PMU_WIRE_PORT); - if (!PMU->init()) - { + if (!PMU->init()) { // Serial.println("Warning: Failed to find AXP192 power management"); delete PMU; PMU = NULL; } - else - { + else { // Serial.println("AXP192 PMU init succeeded, using AXP192 PMU"); } } - if (!PMU) - { + if (!PMU) { MESH_DEBUG_PRINTLN("PMU init failed."); return false; } // Serial.printf("PMU ID:0x%x\n", PMU->getChipID()); // printPMU(); - if (PMU->getChipModel() == XPOWERS_AXP192) - { + if (PMU->getChipModel() == XPOWERS_AXP192) { // lora radio power channel PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300); PMU->enablePowerOutput(XPOWERS_LDO2); @@ -95,8 +86,7 @@ bool TBeamBoard::power_init() PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ); PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_550MA); } - else if (PMU->getChipModel() == XPOWERS_AXP2101) - { + else if (PMU->getChipModel() == XPOWERS_AXP2101) { // gnss module power channel PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300); PMU->enablePowerOutput(XPOWERS_ALDO4); @@ -144,21 +134,10 @@ bool radio_init() { #if defined(P_LORA_SCLK) spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + return radio.std_init(&spi); +#else + return radio.std_init(); #endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - -#ifdef SX127X_CURRENT_LIMIT - radio.setCurrentLimit(SX127X_CURRENT_LIMIT); -#endif - - radio.setCRC(1); - - return true; // success } uint32_t radio_get_rng_seed() { @@ -182,22 +161,21 @@ mesh::LocalIdentity radio_new_identity() { } #ifdef MESH_DEBUG -void TBeamBoard::printPMU() -{ - Serial.print("isCharging:"); Serial.println(PMU->isCharging() ? "YES" : "NO"); - Serial.print("isDischarge:"); Serial.println(PMU->isDischarge() ? "YES" : "NO"); - Serial.print("isVbusIn:"); Serial.println(PMU->isVbusIn() ? "YES" : "NO"); - Serial.print("getBattVoltage:"); Serial.print(PMU->getBattVoltage()); Serial.println("mV"); - Serial.print("getVbusVoltage:"); Serial.print(PMU->getVbusVoltage()); Serial.println("mV"); - Serial.print("getSystemVoltage:"); Serial.print(PMU->getSystemVoltage()); Serial.println("mV"); +void TBeamBoard::printPMU() { + Serial.print("isCharging:"); Serial.println(PMU->isCharging() ? "YES" : "NO"); + Serial.print("isDischarge:"); Serial.println(PMU->isDischarge() ? "YES" : "NO"); + Serial.print("isVbusIn:"); Serial.println(PMU->isVbusIn() ? "YES" : "NO"); + Serial.print("getBattVoltage:"); Serial.print(PMU->getBattVoltage()); Serial.println("mV"); + Serial.print("getVbusVoltage:"); Serial.print(PMU->getVbusVoltage()); Serial.println("mV"); + Serial.print("getSystemVoltage:"); Serial.print(PMU->getSystemVoltage()); Serial.println("mV"); - // The battery percentage may be inaccurate at first use, the PMU will automatically - // learn the battery curve and will automatically calibrate the battery percentage - // after a charge and discharge cycle - if (PMU->isBatteryConnect()) { - Serial.print("getBatteryPercent:"); Serial.print(PMU->getBatteryPercent()); Serial.println("%"); - } + // The battery percentage may be inaccurate at first use, the PMU will automatically + // learn the battery curve and will automatically calibrate the battery percentage + // after a charge and discharge cycle + if (PMU->isBatteryConnect()) { + Serial.print("getBatteryPercent:"); Serial.print(PMU->getBatteryPercent()); Serial.println("%"); + } - Serial.println(); + Serial.println(); } #endif \ No newline at end of file From 0e197254a25cbbe1d71cb22051482705132e3dc3 Mon Sep 17 00:00:00 2001 From: recrof Date: Fri, 27 Jun 2025 17:38:07 +0200 Subject: [PATCH 13/39] remove old tbeam def --- variants/lilygo_tbeam/target.cpp | 181 ------------------------------- 1 file changed, 181 deletions(-) delete mode 100644 variants/lilygo_tbeam/target.cpp diff --git a/variants/lilygo_tbeam/target.cpp b/variants/lilygo_tbeam/target.cpp deleted file mode 100644 index c482dd04..00000000 --- a/variants/lilygo_tbeam/target.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include -#include "target.h" - -TBeamBoard board; - -// Using PMU AXP2102 -#define PMU_WIRE_PORT Wire - -bool pmuIntFlag = false; -static void setPMUIntFlag(){ - pmuIntFlag = true; -} - -#if defined(P_LORA_SCLK) - static SPIClass spi; - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi); -#else - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1); -#endif - -WRAPPER_CLASS radio_driver(radio, board); - -ESP32RTCClock fallback_clock; -AutoDiscoverRTCClock rtc_clock(fallback_clock); -SensorManager sensors; - -#ifdef DISPLAY_CLASS - DISPLAY_CLASS display; -#endif - -#ifndef LORA_CR - #define LORA_CR 5 -#endif - -bool TBeamBoard::power_init() { - if (!PMU) { - PMU = new XPowersAXP2101(PMU_WIRE_PORT); - if (!PMU->init()) { - // Serial.println("Warning: Failed to find AXP2101 power management"); - delete PMU; - PMU = NULL; - } - else { - // Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU"); - } - } - if (!PMU) { - PMU = new XPowersAXP192(PMU_WIRE_PORT); - if (!PMU->init()) { - // Serial.println("Warning: Failed to find AXP192 power management"); - delete PMU; - PMU = NULL; - } - else { - // Serial.println("AXP192 PMU init succeeded, using AXP192 PMU"); - } - } - - if (!PMU) { - MESH_DEBUG_PRINTLN("PMU init failed."); - return false; - } - - // Serial.printf("PMU ID:0x%x\n", PMU->getChipID()); - // printPMU(); - if (PMU->getChipModel() == XPOWERS_AXP192) { - // lora radio power channel - PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300); - PMU->enablePowerOutput(XPOWERS_LDO2); - // oled module power channel, - // disable it will cause abnormal communication between boot and AXP power supply, - // do not turn it off - PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300); - // enable oled power - PMU->enablePowerOutput(XPOWERS_DCDC1); - // gnss module power channel - PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300); - // power->enablePowerOutput(XPOWERS_LDO3); - // protected oled power source - PMU->setProtectedChannel(XPOWERS_DCDC1); - // protected esp32 power source - PMU->setProtectedChannel(XPOWERS_DCDC3); - // disable not use channel - PMU->disablePowerOutput(XPOWERS_DCDC2); - // disable all axp chip interrupt - PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ); - PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_550MA); - } - else if (PMU->getChipModel() == XPOWERS_AXP2101) { - // gnss module power channel - PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300); - PMU->enablePowerOutput(XPOWERS_ALDO4); - // lora radio power channel - PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); - PMU->enablePowerOutput(XPOWERS_ALDO3); - // m.2 interface - PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300); - PMU->enablePowerOutput(XPOWERS_DCDC3); - // power->setPowerChannelVoltage(XPOWERS_DCDC4, 3300); - // power->enablePowerOutput(XPOWERS_DCDC4); - // not use channel - PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited - PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited - PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist - PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist - PMU->disablePowerOutput(XPOWERS_VBACKUP); - // disable all axp chip interrupt - PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ); - PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA); - - // Set up PMU interrupts - // Serial.println("Setting up PMU interrupts"); - pinMode(PIN_PMU_IRQ, INPUT_PULLUP); - attachInterrupt(PIN_PMU_IRQ, setPMUIntFlag, FALLING); - - // Reset and re-enable PMU interrupts - // Serial.println("Re-enable interrupts"); - PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ); - PMU->clearIrqStatus(); - PMU->enableIRQ( - XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // Battery interrupts - XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS interrupts - XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // Power Key interrupts - XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // Charging interrupts - ); - } - - return true; -} - -bool radio_init() { - fallback_clock.begin(); - rtc_clock.begin(Wire); - -#if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); - 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 -} - -#ifdef MESH_DEBUG -void TBeamBoard::printPMU() { - Serial.print("isCharging:"); Serial.println(PMU->isCharging() ? "YES" : "NO"); - Serial.print("isDischarge:"); Serial.println(PMU->isDischarge() ? "YES" : "NO"); - Serial.print("isVbusIn:"); Serial.println(PMU->isVbusIn() ? "YES" : "NO"); - Serial.print("getBattVoltage:"); Serial.print(PMU->getBattVoltage()); Serial.println("mV"); - Serial.print("getVbusVoltage:"); Serial.print(PMU->getVbusVoltage()); Serial.println("mV"); - Serial.print("getSystemVoltage:"); Serial.print(PMU->getSystemVoltage()); Serial.println("mV"); - - // The battery percentage may be inaccurate at first use, the PMU will automatically - // learn the battery curve and will automatically calibrate the battery percentage - // after a charge and discharge cycle - if (PMU->isBatteryConnect()) { - Serial.print("getBatteryPercent:"); Serial.print(PMU->getBatteryPercent()); Serial.println("%"); - } - - Serial.println(); -} -#endif \ No newline at end of file From e417c43c30b0eb270a8c647c92d2053164111194 Mon Sep 17 00:00:00 2001 From: JQ Date: Fri, 27 Jun 2025 22:57:49 -0700 Subject: [PATCH 14/39] wireless paper board support --- src/helpers/HeltecV3Board.h | 6 +- src/helpers/ui/E213Display.cpp | 116 ++++++++++++++++++ src/helpers/ui/E213Display.h | 37 ++++++ variants/heltec_wireless_paper/platformio.ini | 84 +++++++++++++ variants/heltec_wireless_paper/target.cpp | 44 +++++++ variants/heltec_wireless_paper/target.h | 27 ++++ 6 files changed, 312 insertions(+), 2 deletions(-) create mode 100644 src/helpers/ui/E213Display.cpp create mode 100644 src/helpers/ui/E213Display.h create mode 100644 variants/heltec_wireless_paper/platformio.ini create mode 100644 variants/heltec_wireless_paper/target.cpp create mode 100644 variants/heltec_wireless_paper/target.h diff --git a/src/helpers/HeltecV3Board.h b/src/helpers/HeltecV3Board.h index 57015a04..b71514cc 100644 --- a/src/helpers/HeltecV3Board.h +++ b/src/helpers/HeltecV3Board.h @@ -4,7 +4,7 @@ #include // LoRa radio module pins for Heltec V3 -// Also for Heltec Wireless Tracker +// Also for Heltec Wireless Tracker/Paper #define P_LORA_DIO_1 14 #define P_LORA_NSS 8 #define P_LORA_RESET RADIOLIB_NC @@ -14,7 +14,9 @@ #define P_LORA_MOSI 10 // built-ins -#define PIN_VBAT_READ 1 +#ifndef PIN_VBAT_READ // set in platformio.ini for boards like Heltec Wireless Paper (20) + #define PIN_VBAT_READ 1 +#endif #ifndef PIN_ADC_CTRL // set in platformio.ini for Heltec Wireless Tracker (2) #define PIN_ADC_CTRL 37 #endif diff --git a/src/helpers/ui/E213Display.cpp b/src/helpers/ui/E213Display.cpp new file mode 100644 index 00000000..5ec30b00 --- /dev/null +++ b/src/helpers/ui/E213Display.cpp @@ -0,0 +1,116 @@ +#include "E213Display.h" +#include "../../MeshCore.h" + +bool E213Display::begin() { + if (_init) return true; + + powerOn(); + display.begin(); + + // Set to landscape mode rotated 180 degrees + display.setRotation(3); + + _init = true; + _isOn = true; + + clear(); + display.fastmodeOn(); // Enable fast mode for quicker (partial) updates + + return true; +} + +void E213Display::powerOn() { + #ifdef PIN_VEXT_EN + pinMode(PIN_VEXT_EN, OUTPUT); + digitalWrite(PIN_VEXT_EN, LOW); // Active low + delay(50); // Allow power to stabilize + #endif +} + +void E213Display::powerOff() { + #ifdef PIN_VEXT_EN + digitalWrite(PIN_VEXT_EN, HIGH); // Turn off power + #endif +} + +void E213Display::turnOn() { + if (!_init) begin(); + powerOn(); + _isOn = true; +} + +void E213Display::turnOff() { + powerOff(); + _isOn = false; +} + +void E213Display::clear() { + display.clear(); +} + +void E213Display::startFrame(Color bkg) { + // Fill screen with white first to ensure clean background + display.fillRect(0, 0, width(), height(), WHITE); + if (bkg == LIGHT) { + // Fill with black if light background requested (inverted for e-ink) + display.fillRect(0, 0, width(), height(), BLACK); + } +} + +void E213Display::setTextSize(int sz) { + // The library handles text size internally + display.setTextSize(sz); +} + +void E213Display::setColor(Color c) { + // implemented in individual display methods +} + +void E213Display::setCursor(int x, int y) { + display.setCursor(x, y); +} + +void E213Display::print(const char* str) { + display.print(str); +} + +void E213Display::fillRect(int x, int y, int w, int h) { + display.fillRect(x, y, w, h, BLACK); +} + +void E213Display::drawRect(int x, int y, int w, int h) { + display.drawRect(x, y, w, h, BLACK); +} + +void E213Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { + // Width in bytes for bitmap processing + uint16_t widthInBytes = (w + 7) / 8; + + // Process the bitmap row by row + for (int by = 0; by < h; by++) { + // Scan across the row bit by bit + for (int bx = 0; bx < w; bx++) { + // Get the current bit using MSB ordering (like GxEPDDisplay) + uint16_t byteOffset = (by * widthInBytes) + (bx / 8); + uint8_t bitMask = 0x80 >> (bx & 7); + bool bitSet = bits[byteOffset] & bitMask; + + // If the bit is set, draw the pixel + if (bitSet) { + display.drawPixel(x + bx, y + by, BLACK); + } + } + } +} + +uint16_t E213Display::getTextWidth(const char* str) { + int16_t x1, y1; + uint16_t w, h; + display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h); + return w; +} + +void E213Display::endFrame() { + display.update(); +} + diff --git a/src/helpers/ui/E213Display.h b/src/helpers/ui/E213Display.h new file mode 100644 index 00000000..d568b45f --- /dev/null +++ b/src/helpers/ui/E213Display.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include "DisplayDriver.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(); +}; \ No newline at end of file diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini new file mode 100644 index 00000000..0b9ac38e --- /dev/null +++ b/variants/heltec_wireless_paper/platformio.ini @@ -0,0 +1,84 @@ +[Heltec_Wireless_Paper_base] +extends = esp32_base +board = esp32-s3-devkitc-1 +build_flags = + ${esp32_base.build_flags} + -I variants/heltec_wireless_paper + -D HELTEC_WIRELESS_PAPER + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D P_LORA_TX_LED=18 + ; -D PIN_BOARD_SDA=17 + ; -D PIN_BOARD_SCL=18 + -D PIN_USER_BTN=0 + -D PIN_VEXT_EN=45 + -D PIN_VBAT_READ=20 + -D PIN_ADC_CTRL=19 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D DISP_CS=4 + -D DISP_BUSY=7 + -D DISP_DC=5 + -D DISP_RST=6 + -D DISP_SCLK=3 + -D DISP_MOSI=2 + -D ARDUINO_heltec_wifi_lora_32_V3 + -D WIRELESS_PAPER +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/heltec_wireless_paper> +lib_deps = + ${esp32_base.lib_deps} + todd-herbert/heltec-eink-modules @ 4.5.0 + +[env:Heltec_Wireless_Paper_companion_radio_ble] +extends = Heltec_Wireless_Paper_base +build_flags = + ${Heltec_Wireless_Paper_base.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D DISPLAY_CLASS=E213Display + -D BLE_PIN_CODE=0 ; dynamic, random PIN + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} + + + + + +<../examples/companion_radio> +lib_deps = + ${Heltec_Wireless_Paper_base.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Heltec_Wireless_Paper_repeater] +extends = Heltec_Wireless_Paper_base +build_flags = + ${Heltec_Wireless_Paper_base.build_flags} + -D DISPLAY_CLASS=E213Display + -D ADVERT_NAME='"Heltec WP Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 +build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} + + + +<../examples/simple_repeater> +lib_deps = + ${Heltec_Wireless_Paper_base.lib_deps} + ${esp32_ota.lib_deps} + +[env:Heltec_Wireless_Paper_room_server] +extends = Heltec_Wireless_Paper_base +build_flags = + ${Heltec_Wireless_Paper_base.build_flags} + -D DISPLAY_CLASS=E213Display + -D ADVERT_NAME='"Heltec WP Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} + + + +<../examples/simple_room_server> +lib_deps = + ${Heltec_Wireless_Paper_base.lib_deps} + ${esp32_ota.lib_deps} \ No newline at end of file diff --git a/variants/heltec_wireless_paper/target.cpp b/variants/heltec_wireless_paper/target.cpp new file mode 100644 index 00000000..b2808689 --- /dev/null +++ b/variants/heltec_wireless_paper/target.cpp @@ -0,0 +1,44 @@ +#include +#include "target.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 +} \ No newline at end of file diff --git a/variants/heltec_wireless_paper/target.h b/variants/heltec_wireless_paper/target.h new file mode 100644 index 00000000..e3130308 --- /dev/null +++ b/variants/heltec_wireless_paper/target.h @@ -0,0 +1,27 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include +#endif + +extern HeltecV3Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager sensors; + +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); \ No newline at end of file From 3bd1dc3ffa993ef483c598fc79e58381dc14279e Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sat, 28 Jun 2025 16:10:53 +1000 Subject: [PATCH 15/39] * minor tidy ups --- variants/rak4631/target.cpp | 31 ++++++++++++++----------------- variants/rak4631/target.h | 8 -------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/variants/rak4631/target.cpp b/variants/rak4631/target.cpp index 45d10975..e9d80421 100644 --- a/variants/rak4631/target.cpp +++ b/variants/rak4631/target.cpp @@ -25,14 +25,14 @@ RAK4631SensorManager sensors; #endif #include static Bsec2 BME680; -float rawPressure = 0; -float rawTemperature = 0; -float compTemperature = 0; -float rawHumidity = 0; -float compHumidity = 0; -float readIAQ = 0; -float readStaticIAQ = 0; -float readCO2 = 0; +static float rawPressure = 0; +static float rawTemperature = 0; +static float compTemperature = 0; +static float rawHumidity = 0; +static float compHumidity = 0; +static float readIAQ = 0; +static float readStaticIAQ = 0; +static float readCO2 = 0; #endif #ifdef DISPLAY_CLASS @@ -41,7 +41,7 @@ float readCO2 = 0; #ifdef MESH_DEBUG uint32_t deviceOnline = 0x00; -void scanDevices(TwoWire *w) +static void scanDevices(TwoWire *w) { uint8_t err, addr; int nDevices = 0; @@ -168,8 +168,7 @@ bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){ #endif #if ENV_INCLUDE_BME680 -void checkBMEStatus(Bsec2 bsec) -{ +static void checkBMEStatus(Bsec2 bsec) { if (bsec.status < BSEC_OK) { MESH_DEBUG_PRINTLN("BSEC error code : %f", float(bsec.status)); @@ -188,17 +187,15 @@ void checkBMEStatus(Bsec2 bsec) MESH_DEBUG_PRINTLN("BME68X warning code : %f", bsec.sensor.status); } } -void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec) -{ - if (!outputs.nOutputs) - { + +static void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec) { + if (!outputs.nOutputs) { MESH_DEBUG_PRINTLN("No new data to report out"); return; } MESH_DEBUG_PRINTLN("BSEC outputs:\n\tTime stamp = %f", (int) (outputs.output[0].time_stamp / INT64_C(1000000))); - for (uint8_t i = 0; i < outputs.nOutputs; i++) - { + for (uint8_t i = 0; i < outputs.nOutputs; i++) { const bsecData output = outputs.output[i]; switch (output.sensor_id) { diff --git a/variants/rak4631/target.h b/variants/rak4631/target.h index 0460c9e8..3f26ab33 100644 --- a/variants/rak4631/target.h +++ b/variants/rak4631/target.h @@ -11,9 +11,6 @@ #include #include #endif -#if ENV_INCLUDE_BME680 - #include "bsec2.h" -#endif #ifdef DISPLAY_CLASS #include #endif @@ -84,11 +81,6 @@ enum { RAK12500_ONLINE = _BV(14), }; -#if ENV_INCLUDE_BME680 - void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec); - void checkBMEStatus(Bsec2 bsec); -#endif - bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); From ff3e888dfd7ad139ff77be492faf7bbf44a7d0a1 Mon Sep 17 00:00:00 2001 From: JQ Date: Fri, 27 Jun 2025 23:30:52 -0700 Subject: [PATCH 16/39] formatting --- src/helpers/ui/E213Display.cpp | 38 +++++++++++------------ src/helpers/ui/E213Display.h | 14 ++++----- variants/heltec_wireless_paper/target.cpp | 7 +++-- variants/heltec_wireless_paper/target.h | 10 +++--- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/helpers/ui/E213Display.cpp b/src/helpers/ui/E213Display.cpp index 5ec30b00..92bf37fb 100644 --- a/src/helpers/ui/E213Display.cpp +++ b/src/helpers/ui/E213Display.cpp @@ -1,36 +1,37 @@ #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 +#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 +#ifdef PIN_VEXT_EN + digitalWrite(PIN_VEXT_EN, HIGH); // Turn off power +#endif } void E213Display::turnOn() { @@ -70,7 +71,7 @@ void E213Display::setCursor(int x, int y) { display.setCursor(x, y); } -void E213Display::print(const char* str) { +void E213Display::print(const char *str) { display.print(str); } @@ -82,10 +83,10 @@ 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) { +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 @@ -94,7 +95,7 @@ void E213Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { 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); @@ -103,7 +104,7 @@ void E213Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { } } -uint16_t E213Display::getTextWidth(const char* str) { +uint16_t E213Display::getTextWidth(const char *str) { int16_t x1, y1; uint16_t w, h; display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h); @@ -113,4 +114,3 @@ uint16_t E213Display::getTextWidth(const char* str) { void E213Display::endFrame() { display.update(); } - diff --git a/src/helpers/ui/E213Display.h b/src/helpers/ui/E213Display.h index d568b45f..330a2b6d 100644 --- a/src/helpers/ui/E213Display.h +++ b/src/helpers/ui/E213Display.h @@ -1,9 +1,10 @@ #pragma once +#include "DisplayDriver.h" + #include #include #include -#include "DisplayDriver.h" // Display driver for E213 e-ink display class E213Display : public DisplayDriver { @@ -12,8 +13,7 @@ class E213Display : public DisplayDriver { bool _isOn = false; public: - E213Display() : DisplayDriver(250, 122) { - } + E213Display() : DisplayDriver(250, 122) {} bool begin(); bool isOn() override { return _isOn; } @@ -24,13 +24,13 @@ public: void setTextSize(int sz) override; void setColor(Color c) override; void setCursor(int x, int y) override; - void print(const char* str) 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 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(); diff --git a/variants/heltec_wireless_paper/target.cpp b/variants/heltec_wireless_paper/target.cpp index b2808689..65eaab04 100644 --- a/variants/heltec_wireless_paper/target.cpp +++ b/variants/heltec_wireless_paper/target.cpp @@ -1,6 +1,7 @@ -#include #include "target.h" +#include + HeltecV3Board board; static SPIClass spi; @@ -14,7 +15,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; #ifdef DISPLAY_CLASS - DISPLAY_CLASS display; +DISPLAY_CLASS display; #endif bool radio_init() { @@ -40,5 +41,5 @@ void radio_set_tx_power(uint8_t dbm) { mesh::LocalIdentity radio_new_identity() { RadioNoiseListener rng(radio); - return mesh::LocalIdentity(&rng); // create new random identity + return mesh::LocalIdentity(&rng); // create new random identity } \ No newline at end of file diff --git a/variants/heltec_wireless_paper/target.h b/variants/heltec_wireless_paper/target.h index e3130308..f06eead3 100644 --- a/variants/heltec_wireless_paper/target.h +++ b/variants/heltec_wireless_paper/target.h @@ -2,13 +2,13 @@ #define RADIOLIB_STATIC_ONLY 1 #include -#include -#include -#include #include +#include +#include +#include #include #ifdef DISPLAY_CLASS - #include +#include #endif extern HeltecV3Board board; @@ -17,7 +17,7 @@ extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; #ifdef DISPLAY_CLASS - extern DISPLAY_CLASS display; +extern DISPLAY_CLASS display; #endif bool radio_init(); From 1ce180d6ea5ca427b69e237b6a3ac192aff0da9c Mon Sep 17 00:00:00 2001 From: recrof Date: Sat, 28 Jun 2025 11:00:13 +0200 Subject: [PATCH 17/39] remove spi.begin in targets --- variants/heltec_v2/target.cpp | 1 - variants/lilygo_tbeam_SX1276/target.cpp | 22 +++------------------- variants/lilygo_tlora_v2_1/target.cpp | 1 - 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/variants/heltec_v2/target.cpp b/variants/heltec_v2/target.cpp index d4d21dba..418f1f7f 100644 --- a/variants/heltec_v2/target.cpp +++ b/variants/heltec_v2/target.cpp @@ -25,7 +25,6 @@ bool radio_init() { rtc_clock.begin(Wire); #if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); return radio.std_init(&spi); #else return radio.std_init(); diff --git a/variants/lilygo_tbeam_SX1276/target.cpp b/variants/lilygo_tbeam_SX1276/target.cpp index d340dedb..7e2537bb 100644 --- a/variants/lilygo_tbeam_SX1276/target.cpp +++ b/variants/lilygo_tbeam_SX1276/target.cpp @@ -27,31 +27,15 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); 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) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + return radio.std_init(&spi); +#else + return radio.std_init(); #endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - -#ifdef SX127X_CURRENT_LIMIT - radio.setCurrentLimit(SX127X_CURRENT_LIMIT); -#endif - - radio.setCRC(1); - - return true; // success } uint32_t radio_get_rng_seed() { diff --git a/variants/lilygo_tlora_v2_1/target.cpp b/variants/lilygo_tlora_v2_1/target.cpp index 6f60b979..5e8f15b2 100644 --- a/variants/lilygo_tlora_v2_1/target.cpp +++ b/variants/lilygo_tlora_v2_1/target.cpp @@ -21,7 +21,6 @@ bool radio_init() { rtc_clock.begin(Wire); #if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); return radio.std_init(&spi); #else return radio.std_init(); From 9530744ff4073c641cbe12ea11d86098f59294c6 Mon Sep 17 00:00:00 2001 From: recrof Date: Sun, 29 Jun 2025 00:17:46 +0200 Subject: [PATCH 18/39] add support for BMP280 temperature+pressure sensor --- .../sensors/EnvironmentSensorManager.cpp | 41 ++++++++++++++++--- .../sensors/EnvironmentSensorManager.h | 5 ++- variants/heltec_v3/platformio.ini | 6 ++- variants/lilygo_tlora_v2_1/platformio.ini | 12 ++++++ variants/promicro/platformio.ini | 28 +++++++------ 5 files changed, 69 insertions(+), 23 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index b3de0568..b672cdd4 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -15,6 +15,16 @@ static Adafruit_AHTX0 AHTX0; static Adafruit_BME280 BME280; #endif +#if ENV_INCLUDE_BMP280 +#ifndef TELEM_BMP280_ADDRESS +#define TELEM_BMP280_ADDRESS 0x76 // BMP280 environmental sensor I2C address +#endif +#define TELEM_BMP280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level +#include +static Adafruit_BMP280 BMP280; +#endif + + #if ENV_INCLUDE_INA3221 #define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address #define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts @@ -55,6 +65,17 @@ bool EnvironmentSensorManager::begin() { } #endif + #if ENV_INCLUDE_BMP280 + if (BMP280.begin(TELEM_BMP280_ADDRESS)) { + MESH_DEBUG_PRINTLN("Found BMP280 at address: %02X", TELEM_BMP280_ADDRESS); + MESH_DEBUG_PRINTLN("BMP sensor ID: %02X", BMP280.sensorID()); + BMP280_initialized = true; + } else { + BMP280_initialized = false; + MESH_DEBUG_PRINTLN("BMP280 was not found at I2C address %02X", TELEM_BMP280_ADDRESS); + } + #endif + #if ENV_INCLUDE_INA3221 if (INA3221.begin(TELEM_INA3221_ADDRESS, &Wire)) { MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); @@ -97,7 +118,7 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen sensors_event_t humidity, temp; AHTX0.getEvent(&humidity, &temp); telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); - telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); } #endif @@ -110,6 +131,14 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen } #endif + #if ENV_INCLUDE_BMP280 + if (BMP280_initialized) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, BMP280.readTemperature()); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BMP280.readPressure()); + telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280.readAltitude(TELEM_BME280_SEALEVELPRESSURE_HPA)); + } + #endif + #if ENV_INCLUDE_INA3221 if (INA3221_initialized) { for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) { @@ -152,7 +181,7 @@ int EnvironmentSensorManager::getNumSettings() const { const char* EnvironmentSensorManager::getSettingName(int i) const { #if ENV_INCLUDE_GPS return (gps_detected && i == 0) ? "gps" : NULL; - #else + #else return NULL; #endif } @@ -184,7 +213,7 @@ bool EnvironmentSensorManager::setSettingValue(const char* name, const char* val void EnvironmentSensorManager::initBasicGPS() { Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX); - + #ifdef GPS_BAUD_RATE Serial1.begin(GPS_BAUD_RATE); #else @@ -200,7 +229,7 @@ void EnvironmentSensorManager::initBasicGPS() { #ifndef PIN_GPS_EN MESH_DEBUG_PRINTLN("No GPS wake/reset pin found for this board. Continuing on..."); #endif - + // Give GPS a moment to power up and send data delay(1000); @@ -226,7 +255,7 @@ void EnvironmentSensorManager::start_gps() { gps_active = true; #ifdef PIN_GPS_EN pinMode(PIN_GPS_EN, OUTPUT); - digitalWrite(PIN_GPS_EN, HIGH); + digitalWrite(PIN_GPS_EN, HIGH); return; #endif @@ -241,7 +270,7 @@ void EnvironmentSensorManager::stop_gps() { return; #endif - MESH_DEBUG_PRINTLN("Stop GPS is N/A on this board. Actual GPS state unchanged"); + MESH_DEBUG_PRINTLN("Stop GPS is N/A on this board. Actual GPS state unchanged"); } void EnvironmentSensorManager::loop() { diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index c9ec6870..76bffc48 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -10,9 +10,10 @@ protected: bool AHTX0_initialized = false; bool BME280_initialized = false; + bool BMP280_initialized = false; bool INA3221_initialized = false; bool INA219_initialized = false; - + bool gps_detected = false; bool gps_active = false; @@ -31,7 +32,7 @@ public: EnvironmentSensorManager(){}; #endif bool begin() override; - bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; #if ENV_INCLUDE_GPS void loop() override; #endif diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index 8f9b1a27..17a0899a 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -19,15 +19,16 @@ build_flags = -D SX126X_RX_BOOSTED_GAIN=1 -D ENV_INCLUDE_AHTX0=1 -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_BMP280=1 -D ENV_INCLUDE_INA3221=1 - -D ENV_INCLUDE_INA219=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 build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_v3> - + + + lib_deps = ${esp32_base.lib_deps} adafruit/Adafruit SSD1306 @ ^2.5.13 @@ -35,6 +36,7 @@ lib_deps = 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 stevemarple/MicroNMEA @ ^2.0.6 [env:Heltec_v3_repeater] diff --git a/variants/lilygo_tlora_v2_1/platformio.ini b/variants/lilygo_tlora_v2_1/platformio.ini index d9cecfc2..1ecaf664 100644 --- a/variants/lilygo_tlora_v2_1/platformio.ini +++ b/variants/lilygo_tlora_v2_1/platformio.ini @@ -17,6 +17,8 @@ build_flags = -D P_LORA_MISO=19 ; SPI MISO -D P_LORA_MOSI=27 ; SPI MOSI -D P_LORA_TX_LED=2 ; LED pin for TX indication + -D PIN_BOARD_SDA=21 + -D PIN_BOARD_SCL=22 -D PIN_VBAT_READ=35 ; Battery voltage reading (analog pin) -D PIN_USER_BTN=0 -D ARDUINO_LOOP_STACK_SIZE=16384 @@ -25,11 +27,21 @@ build_flags = -D WRAPPER_CLASS=CustomSX1276Wrapper -D SX127X_CURRENT_LIMIT=120 -D LORA_TX_POWER=20 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_BMP280=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 build_src_filter = ${esp32_base.build_src_filter} +<../variants/lilygo_tlora_v2_1> + + lib_deps = ${esp32_base.lib_deps} 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 ; === LILYGO T-LoRa V2.1-1.6 with SX1276 environments === [env:LilyGo_TLora_V2_1_1_6_Repeater] diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index e7099d1e..246019c2 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -1,7 +1,7 @@ [Faketec] -extends = nrf52840_base +extends = nrf52_base board = promicro_nrf52840 -build_flags = ${nrf52840_base.build_flags} +build_flags = ${nrf52_base.build_flags} -I variants/promicro -D FAKETEC -D RADIO_CLASS=CustomSX1262 @@ -19,20 +19,22 @@ build_flags = ${nrf52840_base.build_flags} -D ENV_INCLUDE_GPS=1 -D ENV_INCLUDE_AHTX0=1 -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_BMP280=1 -D ENV_INCLUDE_INA3221=1 -D ENV_INCLUDE_INA219=1 -build_src_filter = ${nrf52840_base.build_src_filter} +build_src_filter = ${nrf52_base.build_src_filter} + - + + + +<../variants/promicro> -lib_deps= ${nrf52840_base.lib_deps} +lib_deps= ${nrf52_base.lib_deps} 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 + adafruit/Adafruit BME280 Library @ ^2.3.0 + adafruit/Adafruit BMP280 Library@^2.6.8 stevemarple/MicroNMEA @ ^2.0.6 - + [env:Faketec_Repeater] extends = Faketec build_src_filter = ${Faketec.build_src_filter} @@ -116,9 +118,9 @@ lib_deps = ${Faketec.lib_deps} densaugeo/base64 @ ~1.4.0 [ProMicroLLCC68] -extends = nrf52840_base +extends = nrf52_base board = promicro_nrf52840 -build_flags = ${nrf52840_base.build_flags} +build_flags = ${nrf52_base.build_flags} -I variants/promicro -D PROMICROLLCC68 -D RADIO_CLASS=CustomLLCC68 @@ -127,15 +129,15 @@ build_flags = ${nrf52840_base.build_flags} -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 build_src_filter = - ${nrf52840_base.build_src_filter} + ${nrf52_base.build_src_filter} + - + + + +<../variants/promicro> -lib_deps= ${nrf52840_base.lib_deps} +lib_deps= ${nrf52_base.lib_deps} 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 BME280 Library @ ^2.3.0 [env:ProMicroLLCC68_Repeater] extends = ProMicroLLCC68 From bcd31b7cdfea5f67c4957fcabda4f1ff3496a541 Mon Sep 17 00:00:00 2001 From: recrof Date: Sun, 29 Jun 2025 00:28:01 +0200 Subject: [PATCH 19/39] fix: missing dependency --- variants/lilygo_tlora_v2_1/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/lilygo_tlora_v2_1/platformio.ini b/variants/lilygo_tlora_v2_1/platformio.ini index 1ecaf664..71b49aab 100644 --- a/variants/lilygo_tlora_v2_1/platformio.ini +++ b/variants/lilygo_tlora_v2_1/platformio.ini @@ -42,6 +42,7 @@ lib_deps = 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 ; === LILYGO T-LoRa V2.1-1.6 with SX1276 environments === [env:LilyGo_TLora_V2_1_1_6_Repeater] From 187eea1b18f698d5e6a6dd0e1d462da7908cf46f Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sun, 29 Jun 2025 20:03:10 +1000 Subject: [PATCH 20/39] * Preamble now 16 (for most variants) --- src/helpers/CustomLLCC68.h | 4 ++-- src/helpers/CustomSX1262.h | 4 ++-- src/helpers/CustomSX1268.h | 4 ++-- src/helpers/CustomSX1276.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/helpers/CustomLLCC68.h b/src/helpers/CustomLLCC68.h index 52b37a0e..c239cc41 100644 --- a/src/helpers/CustomLLCC68.h +++ b/src/helpers/CustomLLCC68.h @@ -42,12 +42,12 @@ class CustomLLCC68 : public LLCC68 { if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif #endif - int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) { #define SX126X_DIO3_TCXO_VOLTAGE (0.0f); tcxo = SX126X_DIO3_TCXO_VOLTAGE; - status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); } if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/src/helpers/CustomSX1262.h b/src/helpers/CustomSX1262.h index 17673d3a..bfaea7c7 100644 --- a/src/helpers/CustomSX1262.h +++ b/src/helpers/CustomSX1262.h @@ -42,12 +42,12 @@ class CustomSX1262 : public SX1262 { if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif #endif - int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) { #define SX126X_DIO3_TCXO_VOLTAGE (0.0f); tcxo = SX126X_DIO3_TCXO_VOLTAGE; - status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); } if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/src/helpers/CustomSX1268.h b/src/helpers/CustomSX1268.h index eb2d4f12..1e2e2620 100644 --- a/src/helpers/CustomSX1268.h +++ b/src/helpers/CustomSX1268.h @@ -42,12 +42,12 @@ class CustomSX1268 : public SX1268 { if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif #endif - int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) { #define SX126X_DIO3_TCXO_VOLTAGE (0.0f); tcxo = SX126X_DIO3_TCXO_VOLTAGE; - status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); } if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/src/helpers/CustomSX1276.h b/src/helpers/CustomSX1276.h index 8396fe07..bee25274 100644 --- a/src/helpers/CustomSX1276.h +++ b/src/helpers/CustomSX1276.h @@ -39,7 +39,7 @@ class CustomSX1276 : public SX1276 { if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif #endif - int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8); + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16); // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); From 165fb33d5cd37901f2c58e695e67dbd7d24b89e2 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sun, 29 Jun 2025 20:06:24 +1000 Subject: [PATCH 21/39] * ver bump to v1.7.1 --- examples/companion_radio/MyMesh.h | 4 ++-- examples/simple_repeater/main.cpp | 4 ++-- examples/simple_room_server/main.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index eeeff75f..891a390e 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -10,11 +10,11 @@ #define FIRMWARE_VER_CODE 6 #ifndef FIRMWARE_BUILD_DATE -#define FIRMWARE_BUILD_DATE "7 Jun 2025" +#define FIRMWARE_BUILD_DATE "29 Jun 2025" #endif #ifndef FIRMWARE_VERSION -#define FIRMWARE_VERSION "v1.7.0" +#define FIRMWARE_VERSION "v1.7.1" #endif #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index c33cadda..8b797991 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "7 Jun 2025" + #define FIRMWARE_BUILD_DATE "29 Jun 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.7.0" + #define FIRMWARE_VERSION "v1.7.1" #endif #ifndef LORA_FREQ diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index f5c1e9dc..3d6cf80b 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "7 Jun 2025" + #define FIRMWARE_BUILD_DATE "29 Jun 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.7.0" + #define FIRMWARE_VERSION "v1.7.1" #endif #ifndef LORA_FREQ From ddbf27c245fd27aa346f996f8f1477b99030790f Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:16:02 +0200 Subject: [PATCH 22/39] change fixed preamble to match the new 16 --- src/helpers/CustomLR1110Wrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/CustomLR1110Wrapper.h b/src/helpers/CustomLR1110Wrapper.h index 7e2ffa2d..947bb51d 100644 --- a/src/helpers/CustomLR1110Wrapper.h +++ b/src/helpers/CustomLR1110Wrapper.h @@ -17,7 +17,7 @@ public: void onSendFinished() override { RadioLibWrapper::onSendFinished(); - _radio->setPreambleLength(8); // overcomes weird issues with small and big pkts + _radio->setPreambleLength(16); // overcomes weird issues with small and big pkts } float getLastRSSI() const override { return ((CustomLR1110 *)_radio)->getRSSI(); } From 1bfa3d338c8821590e9132117604612bb41cf560 Mon Sep 17 00:00:00 2001 From: seagull9000 Date: Mon, 30 Jun 2025 09:48:18 +1200 Subject: [PATCH 23/39] Refactor radiolib for Heltec Wireless Tracker Made changes and tested transmission and reception. Note: TX to T1000E would not work direct, but always went through a repeater. TX to two Thinknode M1's went through direct.. --- variants/heltec_tracker/target.cpp | 33 +++--------------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/variants/heltec_tracker/target.cpp b/variants/heltec_tracker/target.cpp index 042c7c0d..f41702c5 100644 --- a/variants/heltec_tracker/target.cpp +++ b/variants/heltec_tracker/target.cpp @@ -23,43 +23,16 @@ HWTSensorManager sensors = HWTSensorManager(nmea); DISPLAY_CLASS display(&board.periph_power); // peripheral power pin is shared #endif -#ifndef LORA_CR - #define LORA_CR 5 -#endif - bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire); -#ifdef SX126X_DIO3_TCXO_VOLTAGE - float tcxo = SX126X_DIO3_TCXO_VOLTAGE; -#else - float tcxo = 1.6f; -#endif - #if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); -#endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - - radio.setCRC(1); - -#ifdef SX126X_CURRENT_LIMIT - radio.setCurrentLimit(SX126X_CURRENT_LIMIT); -#endif -#ifdef SX126X_DIO2_AS_RF_SWITCH - radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); -#endif -#ifdef SX126X_RX_BOOSTED_GAIN - radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); + return radio.std_init(&spi); +#else + return radio.std_init(); #endif - return true; // success } uint32_t radio_get_rng_seed() { From c56da5e6aa9708ee711bac37b53bc54ddb80956e Mon Sep 17 00:00:00 2001 From: taco Date: Mon, 30 Jun 2025 08:51:18 +1000 Subject: [PATCH 24/39] refactor: lilgo_t3s3 with CustomSX1262::std_init() --- variants/lilygo_t3s3/target.cpp | 39 +++------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/variants/lilygo_t3s3/target.cpp b/variants/lilygo_t3s3/target.cpp index 7fa45e54..b7c4542c 100644 --- a/variants/lilygo_t3s3/target.cpp +++ b/variants/lilygo_t3s3/target.cpp @@ -3,13 +3,8 @@ ESP32Board board; -#if defined(P_LORA_SCLK) - static SPIClass spi; - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); -#else - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); -#endif - +static SPIClass spi; +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); WRAPPER_CLASS radio_driver(radio, board); ESP32RTCClock fallback_clock; @@ -28,35 +23,7 @@ bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire); -#ifdef SX126X_DIO3_TCXO_VOLTAGE - float tcxo = SX126X_DIO3_TCXO_VOLTAGE; -#else - float tcxo = 1.6f; -#endif - -#if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); -#endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - - radio.setCRC(1); - -#ifdef SX126X_CURRENT_LIMIT - radio.setCurrentLimit(SX126X_CURRENT_LIMIT); -#endif -#ifdef SX126X_DIO2_AS_RF_SWITCH - radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); -#endif -#ifdef SX126X_RX_BOOSTED_GAIN - radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); -#endif - - return true; // success + return radio.std_init(&spi); } uint32_t radio_get_rng_seed() { From 4541380632a791dd7e2de70ea1c1e36f2f9d85a9 Mon Sep 17 00:00:00 2001 From: jankowski-t Date: Mon, 30 Jun 2025 03:46:18 +0200 Subject: [PATCH 25/39] Support MeshAdventurer Added support for MeshAdventurer, including radio, display, button, GPS, voltage reading --- src/helpers/MeshadventurerBoard.h | 81 +++++++++ variants/meshadventurer/platformio.ini | 234 +++++++++++++++++++++++++ variants/meshadventurer/target.cpp | 152 ++++++++++++++++ variants/meshadventurer/target.h | 46 +++++ variants/meshadventurer/variant.h | 44 +++++ 5 files changed, 557 insertions(+) create mode 100644 src/helpers/MeshadventurerBoard.h create mode 100644 variants/meshadventurer/platformio.ini create mode 100644 variants/meshadventurer/target.cpp create mode 100644 variants/meshadventurer/target.h create mode 100644 variants/meshadventurer/variant.h diff --git a/src/helpers/MeshadventurerBoard.h b/src/helpers/MeshadventurerBoard.h new file mode 100644 index 00000000..65e11102 --- /dev/null +++ b/src/helpers/MeshadventurerBoard.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +// LoRa radio module pins for Meshadventurer +#define P_LORA_DIO_1 33 +#define P_LORA_NSS 18 +#define P_LORA_RESET 23 +#define P_LORA_BUSY 32 +#define P_LORA_SCLK 5 +#define P_LORA_MISO 19 +#define P_LORA_MOSI 27 + +#define PIN_VBAT_READ 35 + +#include "ESP32Board.h" + +#include + +class MeshadventurerBoard : public ESP32Board { + +public: + void begin() { + ESP32Board::begin(); + + esp_reset_reason_t reason = esp_reset_reason(); + if (reason == ESP_RST_DEEPSLEEP) { + long wakeup_source = esp_sleep_get_ext1_wakeup_status(); + if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep) + startup_reason = BD_STARTUP_RX_PACKET; + } + + rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS); + rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1); + } + } + + void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) { + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + + // Make sure the DIO1 and NSS GPIOs are held on required levels during deep sleep + rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); + + rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); + + if (pin_wake_btn < 0) { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet + } else { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn + } + + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); + } + + // Finally set ESP32 into sleep + esp_deep_sleep_start(); // CPU halts here and never returns! + } + + void powerOff() override { + // TODO: re-enable this when there is a definite wake-up source pin: + // enterDeepSleep(0); + } + + uint16_t getBattMilliVolts() override { + analogReadResolution(12); + + uint32_t raw = 0; + for (int i = 0; i < 4; i++) { + raw += analogReadMilliVolts(PIN_VBAT_READ); + } + raw = raw / 4; + + return (2 * raw); + } + + const char* getManufacturerName() const override { + return "Meshadventurer"; + } +}; diff --git a/variants/meshadventurer/platformio.ini b/variants/meshadventurer/platformio.ini new file mode 100644 index 00000000..5fea4103 --- /dev/null +++ b/variants/meshadventurer/platformio.ini @@ -0,0 +1,234 @@ +[Meshadventurer] +extends = esp32_base +board = esp32doit-devkit-v1 +board_build.partitions = min_spiffs.csv ; get around 4mb flash limit +build_flags = + ${esp32_base.build_flags} + -I variants/meshadventurer + -D MESHADVENTURER + -D P_LORA_TX_LED=2 + -D PIN_VBAT_READ=35 + -D PIN_USER_BTN_ANA=39 + -D P_LORA_DIO_1=33 + -D P_LORA_NSS=18 + -D P_LORA_RESET=23 + -D P_LORA_BUSY=32 + -D P_LORA_SCLK=5 + -D P_LORA_MOSI=27 + -D P_LORA_MISO=19 + -D SX126X_TXEN=13 + -D SX126X_RXEN=14 + -D PIN_BOARD_SDA=21 + -D PIN_BOARD_SCL=22 + -D SX126X_DIO2_AS_RF_SWITCH=false + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_RX_BOOSTED_GAIN=1 + -D PIN_GPS_RX=12 + -D PIN_GPS_TX=15 + -D DISPLAY_CLASS=SSD1306Display +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/meshadventurer> +lib_deps = + ${esp32_base.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 + adafruit/Adafruit SSD1306 @ ^2.5.13 + +[env:Meshadventurer_sx1262_repeater] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_repeater/main.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/main.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> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1262_companion_radio_ble] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1262_terminal_chat] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> + + +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1262_room_server] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_room_server> + + +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} + +[env:Meshadventurer_sx1268_companion_radio_usb] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1268_companion_radio_ble] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1268_terminal_chat] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> + + +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1268_room_server] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_room_server> + + +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} \ No newline at end of file diff --git a/variants/meshadventurer/target.cpp b/variants/meshadventurer/target.cpp new file mode 100644 index 00000000..43e171c0 --- /dev/null +++ b/variants/meshadventurer/target.cpp @@ -0,0 +1,152 @@ +#include +#include "target.h" + +#include + +MeshadventurerBoard 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 + +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); + +#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); + +#if defined(SX126X_RXEN) && defined(SX126X_TXEN) + radio.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN); +#endif + +#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 +} + +void MASensorManager::start_gps() { + if(!gps_active) { + MESH_DEBUG_PRINTLN("starting GPS"); + gps_active = true; + } +} + +void MASensorManager::stop_gps() { + if(gps_active) { + MESH_DEBUG_PRINTLN("stopping GPS"); + gps_active = false; + } +} + +bool MASensorManager::begin() { + Serial1.setPins(PIN_GPS_RX, PIN_GPS_TX); + Serial1.begin(9600); + delay(500); + return true; +} + +bool MASensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + if(requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); + } + return true; +} + +void MASensorManager::loop() { + static long next_gps_update = 0; + _location->loop(); + if(millis() > next_gps_update && gps_active) { + if(_location->isValid()) { + node_lat = ((double)_location->getLatitude()) / 1000000.; + node_lon = ((double)_location->getLongitude()) / 1000000.; + node_altitude = ((double)_location->getAltitude()) / 1000.0; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + next_gps_update = millis() + 1000; + } +} + +int MASensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) + +const char* MASensorManager::getSettingName(int i) const { + return i == 0 ? "gps" : NULL; +} +const char* MASensorManager::getSettingValue(int i) const { + if(i == 0) { + return gps_active ? "1" : "0"; + } + return NULL; +} +bool MASensorManager::setSettingValue(const char* name, const char* value) { + if(strcmp(name, "gps") == 0) { + if(strcmp(value, "0") == 0) { + stop_gps(); + } else { + start_gps(); + } + return true; + } + return false; // not supported +} diff --git a/variants/meshadventurer/target.h b/variants/meshadventurer/target.h new file mode 100644 index 00000000..0e0235ba --- /dev/null +++ b/variants/meshadventurer/target.h @@ -0,0 +1,46 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include +#endif + +class MASensorManager : public SensorManager { + bool gps_active = false; + LocationProvider * _location; + + void start_gps(); + void stop_gps(); +public: + MASensorManager(LocationProvider &location): _location(&location) { } + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + void loop() override; + int getNumSettings() const override; + const char* getSettingName(int i) const override; + const char* getSettingValue(int i) const override; + bool setSettingValue(const char* name, const char* value) override; +}; + +extern MeshadventurerBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern MASensorManager sensors; + +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/meshadventurer/variant.h b/variants/meshadventurer/variant.h new file mode 100644 index 00000000..356a3e17 --- /dev/null +++ b/variants/meshadventurer/variant.h @@ -0,0 +1,44 @@ +// For OLED LCD +#define I2C_SDA 21 +#define I2C_SCL 22 + +// For GPS, 'undef's not needed +#define GPS_TX_PIN 15 +#define GPS_RX_PIN 12 +#define PIN_GPS_EN 4 +#define GPS_POWER_TOGGLE // Moved definition from platformio.ini to here + +#define BUTTON_PIN 39 // The middle button GPIO on the T-Beam +#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO35_CHANNEL +#define ADC_MULTIPLIER 2 +#define EXT_PWR_DETECT 4 // Pin to detect connected external power source for LILYGO® TTGO T-Energy T18 and other DIY boards +#define EXT_NOTIFY_OUT 12 // Overridden default pin to use for Ext Notify Module (#975). +#define LED_PIN 2 // add status LED (compatible with core-pcb and DIY targets) + +// Radio +#define USE_SX1262 // E22-900M30S uses SX1262 +#define USE_SX1268 // E22-400M30S uses SX1268 +#define SX126X_MAX_POWER 22 // Outputting 22dBm from SX1262 results in ~30dBm E22-900M30S output (module only uses last stage of the YP2233W PA) +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // E22 series TCXO reference voltage is 1.8V + +#define SX126X_CS 18 // EBYTE module's NSS pin +#define SX126X_SCK 5 // EBYTE module's SCK pin +#define SX126X_MOSI 27 // EBYTE module's MOSI pin +#define SX126X_MISO 19 // EBYTE module's MISO pin +#define SX126X_RESET 23 // EBYTE module's NRST pin +#define SX126X_BUSY 32 // EBYTE module's BUSY pin +#define SX126X_DIO1 33 // EBYTE module's DIO1 pin + +// The E22's TXEN pin is connected to MCU pin, E22's RXEN pin is connected to MCU pin (allows for ramping up PA before transmission +// Don't define DIO2_AS_RF_SWITCH because we only use DIO2 or an MCU pin mutually exclusively to connect to E22's TXEN (to prevent +// a short if they are both connected at the same time and there's a slight non-neglibible delay and/or voltage difference between +// DIO2 and TXEN). +#define SX126X_TXEN 13 // Schematic connects EBYTE module's TXEN pin to MCU +#define SX126X_RXEN 14 // Schematic connects EBYTE module's RXEN pin to MCU + +#define LORA_CS SX126X_CS // Compatibility with variant file configuration structure +#define LORA_SCK SX126X_SCK // Compatibility with variant file configuration structure +#define LORA_MOSI SX126X_MOSI // Compatibility with variant file configuration structure +#define LORA_MISO SX126X_MISO // Compatibility with variant file configuration structure +#define LORA_DIO1 SX126X_DIO1 // Compatibility with variant file configuration structure From c91356016bbcf0366bd0478af9c6f33a00cc2a2d Mon Sep 17 00:00:00 2001 From: jankowski-t Date: Mon, 30 Jun 2025 05:40:07 +0200 Subject: [PATCH 26/39] Fixed MeshAdventurer repeater build failing Update build_src_filter in platformio.ini --- variants/meshadventurer/platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variants/meshadventurer/platformio.ini b/variants/meshadventurer/platformio.ini index 5fea4103..f8995e18 100644 --- a/variants/meshadventurer/platformio.ini +++ b/variants/meshadventurer/platformio.ini @@ -36,7 +36,7 @@ lib_deps = [env:Meshadventurer_sx1262_repeater] extends = Meshadventurer build_src_filter = ${Meshadventurer.build_src_filter} - +<../examples/simple_repeater/main.cpp> + +<../examples/simple_repeater> + build_flags = ${Meshadventurer.build_flags} @@ -57,7 +57,7 @@ lib_deps = [env:Meshadventurer_sx1268_repeater] extends = Meshadventurer build_src_filter = ${Meshadventurer.build_src_filter} - +<../examples/simple_repeater/main.cpp> + +<../examples/simple_repeater> + build_flags = ${Meshadventurer.build_flags} From 8c80c10d2a0bc1dff1853252610154eae0192635 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 30 Jun 2025 18:57:24 +1000 Subject: [PATCH 27/39] * CustomLR1110::getTimeOnAir(), copied from sx1262 --- src/helpers/CustomLR1110.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/helpers/CustomLR1110.h b/src/helpers/CustomLR1110.h index 3451aac1..d431dac1 100644 --- a/src/helpers/CustomLR1110.h +++ b/src/helpers/CustomLR1110.h @@ -9,6 +9,35 @@ class CustomLR1110 : public LR1110 { public: CustomLR1110(Module *mod) : LR1110(mod) { } + RadioLibTime_t getTimeOnAir(size_t len) override { + uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << this->spreadingFactor) / (this->bandwidthKhz * 10) ; + uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) + uint8_t sfCoeff2 = 8; + if(this->spreadingFactor == 5 || this->spreadingFactor == 6) { + sfCoeff1_x4 = 25; // 6.25 * 4 + sfCoeff2 = 0; + } + uint8_t sfDivisor = 4*this->spreadingFactor; + if(symbolLength_us >= 16000) { + sfDivisor = 4*(this->spreadingFactor - 2); + } + const int8_t bitsPerCrc = 16; + const int8_t N_symbol_header = this->headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0; + + // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) + int16_t bitCount = (int16_t) 8 * len + this->crcTypeLoRa * bitsPerCrc - 4 * this->spreadingFactor + sfCoeff2 + N_symbol_header; + if(bitCount < 0) { + bitCount = 0; + } + // add (sfDivisor) - 1 to the numerator to give integer CEIL(...) + uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); + + // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit + uint32_t nSymbol_x4 = (this->preambleLengthLoRa + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (this->codingRate + 4) * 4; + + return((symbolLength_us * nSymbol_x4) / 4); + } + bool isReceiving() { uint16_t irq = getIrqStatus(); bool detected = ((irq & LR1110_IRQ_HEADER_VALID) || (irq & LR1110_IRQ_HAS_PREAMBLE)); From 3dc4607d8960437e4349b9b785eb66cf55610fb1 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 30 Jun 2025 23:18:16 +1000 Subject: [PATCH 28/39] * PAYLOAD_TYPE_PATH: reserving upper 4 bits if 'extra_type' field, for future use --- src/Mesh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mesh.cpp b/src/Mesh.cpp index a6b06c07..87f99878 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -135,7 +135,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)) { From b80d99edd1726d4a602fb9d9f91e0e79bb6b1313 Mon Sep 17 00:00:00 2001 From: Florent de Lamotte Date: Tue, 1 Jul 2025 15:42:54 +0200 Subject: [PATCH 29/39] t1000e: set preamble to 16 at init --- variants/t1000-e/target.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index 49ae26eb..f6fb1f04 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -54,7 +54,7 @@ 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); From 483b31665c31fc25cf8b9b43c34024fb6a591562 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Wed, 2 Jul 2025 21:11:07 +1000 Subject: [PATCH 30/39] * ver bump to v1.7.2 --- examples/companion_radio/MyMesh.h | 4 ++-- examples/simple_repeater/main.cpp | 4 ++-- examples/simple_room_server/main.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 891a390e..247a9b3d 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -10,11 +10,11 @@ #define FIRMWARE_VER_CODE 6 #ifndef FIRMWARE_BUILD_DATE -#define FIRMWARE_BUILD_DATE "29 Jun 2025" +#define FIRMWARE_BUILD_DATE "2 Jul 2025" #endif #ifndef FIRMWARE_VERSION -#define FIRMWARE_VERSION "v1.7.1" +#define FIRMWARE_VERSION "v1.7.2" #endif #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 8b797991..71c9f24a 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "29 Jun 2025" + #define FIRMWARE_BUILD_DATE "2 Jul 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.7.1" + #define FIRMWARE_VERSION "v1.7.2" #endif #ifndef LORA_FREQ diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 3d6cf80b..c394f3e5 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "29 Jun 2025" + #define FIRMWARE_BUILD_DATE "2 Jul 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.7.1" + #define FIRMWARE_VERSION "v1.7.2" #endif #ifndef LORA_FREQ From 3832836eb24093133b86609cb0d677f8d0c5d8c8 Mon Sep 17 00:00:00 2001 From: recrof Date: Wed, 2 Jul 2025 16:42:35 +0200 Subject: [PATCH 31/39] EnvironmentSensorManager: add support for SHTC3 and LPS22HB --- .../sensors/EnvironmentSensorManager.cpp | 78 +++++++++++++++---- .../sensors/EnvironmentSensorManager.h | 2 + 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index b672cdd4..f0480a87 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -24,6 +24,14 @@ static Adafruit_BME280 BME280; static Adafruit_BMP280 BMP280; #endif +#if ENV_INCLUDE_SHTC3 +#include +static Adafruit_SHTC3 SHTC3; +#endif + +#if ENV_INCLUDE_LPS22HB +#include +#endif #if ENV_INCLUDE_INA3221 #define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address @@ -76,28 +84,48 @@ bool EnvironmentSensorManager::begin() { } #endif + #if ENV_INCLUDE_SHTC3 + if (SHTC3.begin()) { + MESH_DEBUG_PRINTLN("Found sensor: SHTC3"); + SHTC3_initialized = true; + } else { + SHTC3_initialized = false; + MESH_DEBUG_PRINTLN("SHTC3 was not found at I2C address %02X", 0x70); + } + #endif + + #if ENV_INCLUDE_LPS22HB + if (BARO.begin()) { + MESH_DEBUG_PRINTLN("Found sensor: LPS22HB"); + LPS22HB_initialized = true; + } else { + LPS22HB_initialized = false; + MESH_DEBUG_PRINTLN("LPS22HB was not found at I2C address %02X", 0x5C); + } + #endif + #if ENV_INCLUDE_INA3221 if (INA3221.begin(TELEM_INA3221_ADDRESS, &Wire)) { - MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); - MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); + MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); + MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); - for(int i = 0; i < 3; i++) { - INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE); - } - INA3221_initialized = true; + for(int i = 0; i < 3; i++) { + INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE); + } + INA3221_initialized = true; } else { - INA3221_initialized = false; - MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); + INA3221_initialized = false; + MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); } #endif #if ENV_INCLUDE_INA219 if (INA219.begin(&Wire)) { - MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); - INA219_initialized = true; + MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); + INA219_initialized = true; } else { - INA219_initialized = false; - MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); + INA219_initialized = false; + MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); } #endif @@ -139,6 +167,24 @@ 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()); + telemetry.addAltitude(TELEM_CHANNEL_SELF, BARO.readAltitude()); + } + #endif + #if ENV_INCLUDE_INA3221 if (INA3221_initialized) { for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) { @@ -157,10 +203,10 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen #if ENV_INCLUDE_INA219 if (INA219_initialized) { - telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V()); - telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000); - telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000); - next_available_channel++; + telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V()); + telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000); + telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000); + next_available_channel++; } #endif diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 76bffc48..f7804431 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -13,6 +13,8 @@ protected: bool BMP280_initialized = false; bool INA3221_initialized = false; bool INA219_initialized = false; + bool SHTC3_initialized = false; + bool LPS22HB_initialized = false; bool gps_detected = false; bool gps_active = false; From 539f99a90f0b9ff32034e8aa3dbce95d4b7791af Mon Sep 17 00:00:00 2001 From: recrof Date: Wed, 2 Jul 2025 16:50:47 +0200 Subject: [PATCH 32/39] removed unsupported(?) readAltitude --- src/helpers/sensors/EnvironmentSensorManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index f0480a87..a424c46b 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -181,7 +181,6 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen if (LPS22HB_initialized) { telemetry.addTemperature(TELEM_CHANNEL_SELF, BARO.readTemperature()); telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BARO.readPressure()); - telemetry.addAltitude(TELEM_CHANNEL_SELF, BARO.readAltitude()); } #endif From dcb7ffa92ee470896380eb191730c4a45b983716 Mon Sep 17 00:00:00 2001 From: JQ Date: Wed, 2 Jul 2025 08:32:36 -0700 Subject: [PATCH 33/39] fixing radio include order for heltec paper --- variants/heltec_wireless_paper/target.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/variants/heltec_wireless_paper/target.h b/variants/heltec_wireless_paper/target.h index f06eead3..7d901c01 100644 --- a/variants/heltec_wireless_paper/target.h +++ b/variants/heltec_wireless_paper/target.h @@ -2,10 +2,10 @@ #define RADIOLIB_STATIC_ONLY 1 #include -#include -#include -#include #include +#include +#include +#include #include #ifdef DISPLAY_CLASS #include From ad2e015a5b35a5f9e4a0aa7584111f728897555a Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Wed, 2 Jul 2025 10:24:45 -0700 Subject: [PATCH 34/39] move rak usr btn to companions repeaters do not typically have user buttons and there is only one analog pin available on most, if not all, base boards. so this allows repeaters to add custom peripherals or alternate battery signals --- variants/rak4631/platformio.ini | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 9391f99b..86879ed7 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -6,8 +6,6 @@ board_check = true build_flags = ${nrf52840_base.build_flags} -I variants/rak4631 -D RAK_4631 - -D PIN_USER_BTN=9 - -D PIN_USER_BTN_ANA=31 -D PIN_BOARD_SCL=14 -D PIN_BOARD_SDA=13 -D PIN_OLED_RESET=-1 @@ -84,6 +82,8 @@ build_src_filter = ${rak4631.build_src_filter} extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -100,6 +100,8 @@ lib_deps = extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -120,6 +122,8 @@ lib_deps = extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -145,6 +149,8 @@ lib_deps = extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=1 ; -D MESH_PACKET_LOGGING=1 From ca422bbafbebea98083d08fadf58902a77363fc3 Mon Sep 17 00:00:00 2001 From: JQ Date: Wed, 2 Jul 2025 14:37:11 -0700 Subject: [PATCH 35/39] fix ble pin --- variants/heltec_wireless_paper/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index 0b9ac38e..513ba4b9 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -40,7 +40,7 @@ build_flags = -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=E213Display - -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 build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} From d23378cff692f0be9ca4245104978536d8729f63 Mon Sep 17 00:00:00 2001 From: WattleFoxxo Date: Thu, 3 Jul 2025 11:42:53 +1000 Subject: [PATCH 36/39] Add XIAO RP2040 support --- src/helpers/rp2040/XiaoRP2040Board.cpp | 30 +++++++ src/helpers/rp2040/XiaoRP2040Board.h | 75 ++++++++++++++++++ variants/xiao_rp2040/platformio.ini | 104 +++++++++++++++++++++++++ variants/xiao_rp2040/target.cpp | 71 +++++++++++++++++ variants/xiao_rp2040/target.h | 21 +++++ 5 files changed, 301 insertions(+) create mode 100644 src/helpers/rp2040/XiaoRP2040Board.cpp create mode 100644 src/helpers/rp2040/XiaoRP2040Board.h create mode 100644 variants/xiao_rp2040/platformio.ini create mode 100644 variants/xiao_rp2040/target.cpp create mode 100644 variants/xiao_rp2040/target.h diff --git a/src/helpers/rp2040/XiaoRP2040Board.cpp b/src/helpers/rp2040/XiaoRP2040Board.cpp new file mode 100644 index 00000000..bb439706 --- /dev/null +++ b/src/helpers/rp2040/XiaoRP2040Board.cpp @@ -0,0 +1,30 @@ +#include "XiaoRP2040Board.h" + +#include +#include + +void XiaoRP2040Board::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + +#ifdef P_LORA_TX_LED + pinMode(P_LORA_TX_LED, OUTPUT); +#endif + +#ifdef PIN_VBAT_READ + pinMode(PIN_VBAT_READ, INPUT); +#endif + +#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) + Wire.setSDA(PIN_BOARD_SDA); + Wire.setSCL(PIN_BOARD_SCL); +#endif + + Wire.begin(); + + delay(10); // give sx1262 some time to power up +} + +bool XiaoRP2040Board::startOTAUpdate(const char *id, char reply[]) { + return false; +} diff --git a/src/helpers/rp2040/XiaoRP2040Board.h b/src/helpers/rp2040/XiaoRP2040Board.h new file mode 100644 index 00000000..c9353906 --- /dev/null +++ b/src/helpers/rp2040/XiaoRP2040Board.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +// LoRa radio module pins for the Xiao RP2040 +// https://wiki.seeedstudio.com/XIAO-RP2040/ + +#define P_LORA_DIO_1 27 // D1 +#define P_LORA_NSS 6 // D4 +#define P_LORA_RESET 28 // D2 +#define P_LORA_BUSY 29 // D3 +#define P_LORA_TX_LED 17 + +#define SX126X_RXEN 7 // D5 +#define SX126X_TXEN -1 + +#define SX126X_DIO2_AS_RF_SWITCH true +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +/* + * This board has no built-in way to read battery voltage. + * Nevertheless it's very easy to make it work, you only require two 1% resistors. + * If your using the WIO SX1262 Addon for xaio, make sure you dont connect D0! + * + * BAT+ -----+ + * | + * VSYS --+ -/\/\/\/\- --+ + * 200k | + * +-- D0 + * | + * GND --+ -/\/\/\/\- --+ + * | 100k + * BAT- -----+ + */ +#define PIN_VBAT_READ 26 // D0 +#define BATTERY_SAMPLES 8 +#define ADC_MULTIPLIER (3.0f * 3.3f * 1000) + +class XiaoRP2040Board : public mesh::MainBoard { +protected: + uint8_t startup_reason; + +public: + void begin(); + uint8_t getStartupReason() const override { return startup_reason; } + +#ifdef P_LORA_TX_LED + void onBeforeTransmit() override { digitalWrite(P_LORA_TX_LED, HIGH); } + void onAfterTransmit() override { digitalWrite(P_LORA_TX_LED, LOW); } +#endif + + + uint16_t getBattMilliVolts() override { +#if defined(PIN_VBAT_READ) && defined(ADC_MULTIPLIER) + analogReadResolution(12); + + uint32_t raw = 0; + for (int i = 0; i < BATTERY_SAMPLES; i++) { + raw += analogRead(PIN_VBAT_READ); + } + raw = raw / BATTERY_SAMPLES; + + return (ADC_MULTIPLIER * raw) / 4096; +#else + return 0; +#endif + } + + const char *getManufacturerName() const override { return "Xiao RP2040"; } + + void reboot() override { rp2040.reboot(); } + + bool startOTAUpdate(const char *id, char reply[]) override; +}; diff --git a/variants/xiao_rp2040/platformio.ini b/variants/xiao_rp2040/platformio.ini new file mode 100644 index 00000000..960fdbba --- /dev/null +++ b/variants/xiao_rp2040/platformio.ini @@ -0,0 +1,104 @@ +[Xiao_rp2040] +extends = rp2040_base + +board = seeed_xiao_rp2040 +board_build.filesystem_size = 0.5m + +build_flags = ${rp2040_base.build_flags} + -I variants/xiao_rp2040 + -D SX126X_CURRENT_LIMIT=140 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D SX126X_RX_BOOSTED_GAIN=1 +; Debug options + ; -D DEBUG_RP2040_WIRE=1 + ; -D DEBUG_RP2040_SPI=1 + ; -D DEBUG_RP2040_CORE=1 + ; -D RADIOLIB_DEBUG_SPI=1 + ; -D DEBUG_RP2040_PORT=Serial + +build_src_filter = ${rp2040_base.build_src_filter} + + + +<../variants/xiao_rp2040> + +lib_deps = ${rp2040_base.lib_deps} + +[env:Xiao_rp2040_Repeater] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D ADVERT_NAME='"Xiao Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/simple_repeater> + +[env:Xiao_rp2040_room_server] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D ADVERT_NAME='"Xiao Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/simple_room_server> + +[env:Xiao_rp2040_companion_radio_usb] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 +; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/companion_radio> +lib_deps = ${Xiao_rp2040.lib_deps} + densaugeo/base64 @ ~1.4.0 + +; [env:Xiao_rp2040_companion_radio_ble] +; extends = Xiao_rp2040 +; build_flags = ${Xiao_rp2040.build_flags} +; -D MAX_CONTACTS=100 +; -D MAX_GROUP_CHANNELS=8 +; -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; ; -D MESH_PACKET_LOGGING=1 +; ; -D MESH_DEBUG=1 +; build_src_filter = ${Xiao_rp2040.build_src_filter} +; +<../examples/companion_radio> +; lib_deps = ${Xiao_rp2040.lib_deps} +; densaugeo/base64 @ ~1.4.0 + +; [env:Xiao_rp2040_companion_radio_wifi] +; extends = Xiao_rp2040 +; build_flags = ${Xiao_rp2040.build_flags} +; -D MAX_CONTACTS=100 +; -D MAX_GROUP_CHANNELS=8 +; -D WIFI_DEBUG_LOGGING=1 +; -D WIFI_SSID='"myssid"' +; -D WIFI_PWD='"mypwd"' +; ; -D MESH_PACKET_LOGGING=1 +; ; -D MESH_DEBUG=1 +; build_src_filter = ${Xiao_rp2040.build_src_filter} +; +<../examples/companion_radio> +; lib_deps = ${Xiao_rp2040.lib_deps} +; densaugeo/base64 @ ~1.4.0 + +[env:Xiao_rp2040_terminal_chat] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> +lib_deps = ${Xiao_rp2040.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/xiao_rp2040/target.cpp b/variants/xiao_rp2040/target.cpp new file mode 100644 index 00000000..a801aae8 --- /dev/null +++ b/variants/xiao_rp2040/target.cpp @@ -0,0 +1,71 @@ +#include "target.h" + +#include +#include + +XiaoRP2040Board board; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); + +WRAPPER_CLASS radio_driver(radio, board); + +VolatileRTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +SensorManager sensors; + +#ifndef LORA_CR +#define LORA_CR 5 +#endif + +bool radio_init() { + rtc_clock.begin(Wire); + +#ifdef SX126X_DIO3_TCXO_VOLTAGE + float tcxo = SX126X_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#ifdef SX126X_CURRENT_LIMIT + radio.setCurrentLimit(SX126X_CURRENT_LIMIT); +#endif + +#ifdef SX126X_DIO2_AS_RF_SWITCH + radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); +#endif + +#ifdef SX126X_RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/xiao_rp2040/target.h b/variants/xiao_rp2040/target.h new file mode 100644 index 00000000..6a3c192b --- /dev/null +++ b/variants/xiao_rp2040/target.h @@ -0,0 +1,21 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 + +#include +#include +#include +#include +#include +#include + +extern XiaoRP2040Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager sensors; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); From 90656e7d06ecf53f320149f1b9ce98e4a02cdf08 Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Thu, 3 Jul 2025 09:18:26 -0700 Subject: [PATCH 37/39] clean up xiao nrf52 move variant specific code out of src/helpers redefine RXEN for alternate radio pinout --- .../nrf52 => variants/xiao_nrf52}/XiaoNrf52Board.cpp | 0 .../helpers/nrf52 => variants/xiao_nrf52}/XiaoNrf52Board.h | 7 +++---- variants/xiao_nrf52/platformio.ini | 3 +-- variants/xiao_nrf52/target.h | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) rename {src/helpers/nrf52 => variants/xiao_nrf52}/XiaoNrf52Board.cpp (100%) rename {src/helpers/nrf52 => variants/xiao_nrf52}/XiaoNrf52Board.h (93%) diff --git a/src/helpers/nrf52/XiaoNrf52Board.cpp b/variants/xiao_nrf52/XiaoNrf52Board.cpp similarity index 100% rename from src/helpers/nrf52/XiaoNrf52Board.cpp rename to variants/xiao_nrf52/XiaoNrf52Board.cpp diff --git a/src/helpers/nrf52/XiaoNrf52Board.h b/variants/xiao_nrf52/XiaoNrf52Board.h similarity index 93% rename from src/helpers/nrf52/XiaoNrf52Board.h rename to variants/xiao_nrf52/XiaoNrf52Board.h index e6c8e7f7..60b9f5bb 100644 --- a/src/helpers/nrf52/XiaoNrf52Board.h +++ b/variants/xiao_nrf52/XiaoNrf52Board.h @@ -5,20 +5,19 @@ #ifdef XIAO_NRF52 -// LoRa radio module pins for Seeed Xiao-nrf52 +// redefine lora pins if using the S3 variant of SX1262 board #ifdef SX1262_XIAO_S3_VARIANT #undef P_LORA_DIO_1 #undef P_LORA_BUSY #undef P_LORA_RESET #undef P_LORA_NSS + #undef SX126X_RXEN #define P_LORA_DIO_1 D0 #define P_LORA_BUSY D1 #define P_LORA_RESET D2 #define P_LORA_NSS D3 + #define SX126X_RXEN D4 #endif -//#define SX126X_POWER_EN 37 - - class XiaoNrf52Board : public mesh::MainBoard { protected: diff --git a/variants/xiao_nrf52/platformio.ini b/variants/xiao_nrf52/platformio.ini index c4934e04..bba3e632 100644 --- a/variants/xiao_nrf52/platformio.ini +++ b/variants/xiao_nrf52/platformio.ini @@ -50,8 +50,7 @@ build_flags = ${nrf52840_xiao.build_flags} -D ENV_INCLUDE_INA219=1 build_src_filter = ${nrf52840_xiao.build_src_filter} + - + - + + + +<../variants/xiao_nrf52> debug_tool = jlink upload_protocol = nrfutil diff --git a/variants/xiao_nrf52/target.h b/variants/xiao_nrf52/target.h index eb299006..c8c6a42a 100644 --- a/variants/xiao_nrf52/target.h +++ b/variants/xiao_nrf52/target.h @@ -3,7 +3,7 @@ #define RADIOLIB_STATIC_ONLY 1 #include #include -#include +#include #include #include #include From 74818d0594b9b5e45e5ffa9b264080497ba76439 Mon Sep 17 00:00:00 2001 From: taco Date: Fri, 4 Jul 2025 13:55:39 +1000 Subject: [PATCH 38/39] fix: change GPS pins Pin 45 and 46 are strapping pins on ESP32-S3, which can lead to unintended consequences on boot. I have amended the pins and added an enable pin as well. --- variants/heltec_v3/platformio.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index c39e9c76..c3bb27b7 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -23,9 +23,9 @@ build_flags = -D ENV_INCLUDE_INA3221=1 -D ENV_INCLUDE_INA219=1 -D ENV_INCLUDE_GPS=1 - -D PIN_GPS_RX=45 - -D PIN_GPS_TX=46 - -D PIN_GPS_EN=-1 + -D PIN_GPS_RX=47 + -D PIN_GPS_TX=48 + -D PIN_GPS_EN=46 build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_v3> + From 2bb7e6dad4e1e622577edb4febbc9bdf10a3eb0a Mon Sep 17 00:00:00 2001 From: taco Date: Fri, 4 Jul 2025 14:12:57 +1000 Subject: [PATCH 39/39] fix: heltec v3: change gps enable pin --- variants/heltec_v3/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index c3bb27b7..a4b6bf6f 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -25,7 +25,7 @@ build_flags = -D ENV_INCLUDE_GPS=1 -D PIN_GPS_RX=47 -D PIN_GPS_TX=48 - -D PIN_GPS_EN=46 + -D PIN_GPS_EN=26 build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_v3> +