diff --git a/docs/faq.md b/docs/faq.md
index c61c8d2b..1c67c9c7 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -64,9 +64,13 @@ 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)
+ - [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: 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
@@ -533,9 +537,57 @@ 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
+
+
+### 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.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:
+
+1. Download nRF's DFU app from iOS App Store or Android's Play Store, you can find the app by searching for `nrf dfu`, the app's full name is `nRF Device Firmware Update`
+2. On flasher.meshcore.co.uk, download the **ZIP** version of the firmware for your nRF device (e.g. RAK or Heltec T114 or Seeed Studio's Xiao)
+3. 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. 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.
+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: How to update ESP32-based devices over the air?
**A:** For ESP32-based devices (e.g. Heltec V3):
@@ -548,22 +600,19 @@ You can get the epoch time on and use it to se
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?
+### 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.
+
+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
-**A:** The steps below work on both Android and iOS as nRF has made both apps' user interface the same on both platforms:
-1. Download nRF's DFU app from iOS App Store or Android's Play Store, you can find the app by searching for `nrf dfu`, the app's full name is `nRF Device Firmware Update`
-2. On flasher.meshcore.co.uk, download the **ZIP** version of the firmware for your nRF device (e.g. RAK or Heltec T114 or Seeed Studio's Xiao)
-3. 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. 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.
---
diff --git a/docs/packet_structure.md b/docs/packet_structure.md
new file mode 100644
index 00000000..4a28526f
--- /dev/null
+++ b/docs/packet_structure.md
@@ -0,0 +1,54 @@
+# Packet Structure
+
+| 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
+
+bit 0 means the lowest bit (1s place)
+
+| Bits | Mask | Field | Description |
+|-------|--------|-----------------|-----------------------------------------------|
+| 0-1 | `0x03` | Route Type | Flood, Direct, Reserved - 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_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
+
+| 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. |
+| `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
+
+| 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. |
diff --git a/docs/payloads.md b/docs/payloads.md
index 2c402102..b094d9a9 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 |
@@ -37,20 +41,29 @@ 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
+
+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 +73,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 +171,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
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 e32676fb..07b68a20 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
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 7d5d4269..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: ");
@@ -67,11 +67,11 @@ class CustomSX1262 : public SX1262 {
setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
#if defined(SX126X_RXEN) || defined(SX126X_TXEN)
- #ifndef SX1262X_RXEN
- #define SX1262X_RXEN RADIOLIB_NC
+ #ifndef SX126X_RXEN
+ #define SX126X_RXEN RADIOLIB_NC
#endif
- #ifndef SX1262X_TXEN
- #define SX1262X_TXEN RADIOLIB_NC
+ #ifndef SX126X_TXEN
+ #define SX126X_TXEN RADIOLIB_NC
#endif
setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
#endif
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 35d879fc..bee25274 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, 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: ");
+ 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/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h
index 4f90296e..e566f929 100644
--- a/src/helpers/ESP32Board.h
+++ b/src/helpers/ESP32Board.h
@@ -51,6 +51,15 @@ public:
void onAfterTransmit() override {
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off
}
+#elif defined(P_LORA_TX_NEOPIXEL_LED)
+ #define NEOPIXEL_BRIGHTNESS 64 // white brightness (max 255)
+
+ void onBeforeTransmit() override {
+ neopixelWrite(P_LORA_TX_NEOPIXEL_LED, NEOPIXEL_BRIGHTNESS, NEOPIXEL_BRIGHTNESS, NEOPIXEL_BRIGHTNESS); // turn TX neopixel on (White)
+ }
+ void onAfterTransmit() override {
+ neopixelWrite(P_LORA_TX_NEOPIXEL_LED, 0, 0, 0); // turn TX neopixel off
+ }
#endif
uint16_t getBattMilliVolts() override {
diff --git a/src/helpers/esp32/TBeamBoard.cpp b/src/helpers/esp32/TBeamBoard.cpp
index 2e3ea040..5f708d71 100644
--- a/src/helpers/esp32/TBeamBoard.cpp
+++ b/src/helpers/esp32/TBeamBoard.cpp
@@ -1,3 +1,5 @@
+#if defined(TBEAM_SUPREME_SX1262) || defined(TBEAM_SX1262) || defined(TBEAM_SX1276)
+
#include
#include "TBeamBoard.h"
//#include
@@ -343,4 +345,6 @@ bool TBeamBoard::power_init()
// }
-#pragma endregion
\ No newline at end of file
+#pragma endregion
+
+#endif
diff --git a/src/helpers/esp32/TBeamBoard.h b/src/helpers/esp32/TBeamBoard.h
index 255a6d22..74baebc3 100644
--- a/src/helpers/esp32/TBeamBoard.h
+++ b/src/helpers/esp32/TBeamBoard.h
@@ -1,5 +1,7 @@
#pragma once
+#if defined(TBEAM_SUPREME_SX1262) || defined(TBEAM_SX1262) || defined(TBEAM_SX1276)
+
#include
#include
#include "XPowersLib.h"
@@ -162,3 +164,5 @@ public:
return "LilyGo T-Beam";
}
};
+
+#endif
diff --git a/src/helpers/nrf52/RAK4631Board.cpp b/src/helpers/nrf52/RAK4631Board.cpp
index c75ecf29..97a96602 100644
--- a/src/helpers/nrf52/RAK4631Board.cpp
+++ b/src/helpers/nrf52/RAK4631Board.cpp
@@ -84,7 +84,7 @@ bool RAK4631Board::startOTAUpdate(const char* id, char reply[]) {
memset(mac_addr, 0, sizeof(mac_addr));
Bluefruit.getAddr(mac_addr);
sprintf(reply, "OK - mac: %02X:%02X:%02X:%02X:%02X:%02X",
- mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
+ mac_addr[5], mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], mac_addr[0]);
return true;
}
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/src/helpers/stm32/STM32Board.h b/src/helpers/stm32/STM32Board.h
index 65c7414b..06bc768f 100644
--- a/src/helpers/stm32/STM32Board.h
+++ b/src/helpers/stm32/STM32Board.h
@@ -23,6 +23,13 @@ public:
}
void reboot() override {
+ NVIC_SystemReset();
+ }
+
+ void powerOff() override {
+ HAL_PWREx_DisableInternalWakeUpLine();
+ __disable_irq();
+ HAL_PWREx_EnterSHUTDOWNMode();
}
#if defined(P_LORA_TX_LED)
diff --git a/variants/heltec_v2/target.cpp b/variants/heltec_v2/target.cpp
index a7e9fa67..418f1f7f 100644
--- a/variants/heltec_v2/target.cpp
+++ b/variants/heltec_v2/target.cpp
@@ -20,31 +20,15 @@ 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/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_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>
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_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/platformio.ini b/variants/lilygo_tlora_v2_1/platformio.ini
index d9cecfc2..71b49aab 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,22 @@ 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
+ 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]
diff --git a/variants/lilygo_tlora_v2_1/target.cpp b/variants/lilygo_tlora_v2_1/target.cpp
index 4d513ed9..5e8f15b2 100644
--- a/variants/lilygo_tlora_v2_1/target.cpp
+++ b/variants/lilygo_tlora_v2_1/target.cpp
@@ -10,35 +10,21 @@ 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);
- 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);
+#if defined(P_LORA_SCLK)
+ 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;
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
diff --git a/variants/rak3x72/platformio.ini b/variants/rak3x72/platformio.ini
index 94e8f595..386866ba 100644
--- a/variants/rak3x72/platformio.ini
+++ b/variants/rak3x72/platformio.ini
@@ -7,6 +7,8 @@ build_flags = ${stm32_base.build_flags}
-D WRAPPER_CLASS=CustomSTM32WLxWrapper
-D SPI_INTERFACES_COUNT=0
-D RX_BOOSTED_GAIN=true
+; -D STM32WL_TCXO_VOLTAGE=1.6 ; defaults to 0 if undef
+; -D LORA_TX_POWER=14 ; Defaults to 22 for HP, 14 is for LP version
-I variants/rak3x72
build_src_filter = ${stm32_base.build_src_filter}
+<../variants/rak3x72>
@@ -14,7 +16,6 @@ build_src_filter = ${stm32_base.build_src_filter}
[env:rak3x72-repeater]
extends = rak3x72
build_flags = ${rak3x72.build_flags}
- -D LORA_TX_POWER=22
-D ADVERT_NAME='"RAK3x72 Repeater"'
-D ADMIN_PASSWORD='"password"'
build_src_filter = ${rak3x72.build_src_filter}
@@ -24,7 +25,6 @@ build_src_filter = ${rak3x72.build_src_filter}
extends = rak3x72
build_flags = ${rak3x72.build_flags}
; -D FORMAT_FS=true
- -D LORA_TX_POWER=22
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
build_src_filter = ${rak3x72.build_src_filter}
diff --git a/variants/rak3x72/target.cpp b/variants/rak3x72/target.cpp
index 4cb5929a..d7070eae 100644
--- a/variants/rak3x72/target.cpp
+++ b/variants/rak3x72/target.cpp
@@ -24,12 +24,21 @@ SensorManager sensors;
#define LORA_CR 5
#endif
+#ifndef STM32WL_TCXO_VOLTAGE
+ // TCXO set to 0 for RAK3172
+ #define STM32WL_TCXO_VOLTAGE 0
+#endif
+
+#ifndef LORA_TX_POWER
+ #define LORA_TX_POWER 22
+#endif
+
bool radio_init() {
// rtc_clock.begin(Wire);
radio.setRfSwitchTable(rfswitch_pins, rfswitch_table);
- int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, 0, 0); // TCXO set to 0 for RAK3172
+ int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, STM32WL_TCXO_VOLTAGE, 0);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
diff --git a/variants/rak3x72/target.h b/variants/rak3x72/target.h
index c39b69b1..6c86a702 100644
--- a/variants/rak3x72/target.h
+++ b/variants/rak3x72/target.h
@@ -18,8 +18,12 @@ public:
}
uint16_t getBattMilliVolts() override {
- uint32_t raw = analogRead(PIN_VBAT_READ);
- return (ADC_MULTIPLIER * raw) / 1024;
+ analogReadResolution(12);
+ uint32_t raw = 0;
+ for (int i=0; i<8;i++) {
+ raw += analogRead(PIN_VBAT_READ);
+ }
+ return ((double)raw) * ADC_MULTIPLIER / 8 / 4096;
}
};
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..e9d80421 100644
--- a/variants/rak4631/target.cpp
+++ b/variants/rak4631/target.cpp
@@ -19,13 +19,29 @@ 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;
+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
DISPLAY_CLASS display;
#endif
#ifdef MESH_DEBUG
uint32_t deviceOnline = 0x00;
-void scanDevices(TwoWire *w)
+static void scanDevices(TwoWire *w)
{
uint8_t err, addr;
int nDevices = 0;
@@ -43,6 +59,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 +157,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 +167,255 @@ bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){
}
#endif
+#if ENV_INCLUDE_BME680
+static void checkBMEStatus(Bsec2 bsec) {
+ if (bsec.status < BSEC_OK)
+ {
+ MESH_DEBUG_PRINTLN("BSEC error code : %f", float(bsec.status));
+ }
+ else if (bsec.status > BSEC_OK)
+ {
+ MESH_DEBUG_PRINTLN("BSEC warning code : %f", float(bsec.status));
+ }
+
+ if (bsec.sensor.status < BME68X_OK)
+ {
+ MESH_DEBUG_PRINTLN("BME68X error code : %f", bsec.sensor.status);
+ }
+ else if (bsec.sensor.status > BME68X_OK)
+ {
+ MESH_DEBUG_PRINTLN("BME68X warning code : %f", bsec.sensor.status);
+ }
+}
+
+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++) {
+ const bsecData output = outputs.output[i];
+ switch (output.sensor_id)
+ {
+ case BSEC_OUTPUT_IAQ:
+ 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", output.signal);
+ break;
+ case BSEC_OUTPUT_RAW_PRESSURE:
+ rawPressure = output.signal;
+ MESH_DEBUG_PRINTLN("\tPressure = %f", output.signal);
+ break;
+ case BSEC_OUTPUT_RAW_HUMIDITY:
+ rawHumidity = output.signal;
+ MESH_DEBUG_PRINTLN("\tHumidity = %f", output.signal);
+ break;
+ case BSEC_OUTPUT_RAW_GAS:
+ MESH_DEBUG_PRINTLN("\tGas resistance = %f", output.signal);
+ break;
+ case BSEC_OUTPUT_STABILIZATION_STATUS:
+ MESH_DEBUG_PRINTLN("\tStabilization status = %f", output.signal);
+ break;
+ case BSEC_OUTPUT_RUN_IN_STATUS:
+ 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", output.signal);
+ break;
+ case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
+ compHumidity = output.signal;
+ MESH_DEBUG_PRINTLN("\tCompensated humidity = %f", output.signal);
+ break;
+ case BSEC_OUTPUT_STATIC_IAQ:
+ 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", output.signal);
+ break;
+ case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
+ MESH_DEBUG_PRINTLN("\tbVOC equivalent = %f", output.signal);
+ break;
+ case BSEC_OUTPUT_GAS_PERCENTAGE:
+ MESH_DEBUG_PRINTLN("\tGas percentage = %f", output.signal);
+ break;
+ case BSEC_OUTPUT_COMPENSATED_GAS:
+ MESH_DEBUG_PRINTLN("\tCompensated gas = %f", 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[5] = {
+ 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.addTemperature(TELEM_CHANNEL_SELF+1, readIAQ);
+ telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF+1, readStaticIAQ);
+ }
+ #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..3f26ab33 100644
--- a/variants/rak4631/target.h
+++ b/variants/rak4631/target.h
@@ -20,7 +20,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 +32,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;
diff --git a/variants/station_g2/platformio.ini b/variants/station_g2/platformio.ini
index 8ba368bd..5d9a6823 100644
--- a/variants/station_g2/platformio.ini
+++ b/variants/station_g2/platformio.ini
@@ -7,7 +7,7 @@ build_flags =
-D STATION_G2
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
- -D LORA_TX_POWER=7
+ -D LORA_TX_POWER=19
; -D P_LORA_TX_LED=35
-D PIN_BOARD_SDA=5
-D PIN_BOARD_SCL=6
@@ -16,9 +16,9 @@ build_flags =
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
; -D SX126X_RX_BOOSTED_GAIN=1 - DO NOT ENABLE THIS!
+; https://wiki.uniteng.com/en/meshtastic/station-g2#impact-of-lora-node-dense-areashigh-noise-environments-on-rf-performance
-I src/helpers/ui
-D DISPLAY_CLASS=SH1106Display
-; https://wiki.uniteng.com/en/meshtastic/station-g2#impact-of-lora-node-dense-areashigh-noise-environments-on-rf-performance
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/station_g2>
+
diff --git a/variants/station_g2/target.cpp b/variants/station_g2/target.cpp
index dca94f21..2b19f5f0 100644
--- a/variants/station_g2/target.cpp
+++ b/variants/station_g2/target.cpp
@@ -27,36 +27,13 @@ SensorManager sensors;
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);
+ 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, 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() {
diff --git a/variants/tenstar_c3/platformio.ini b/variants/tenstar_c3/platformio.ini
new file mode 100644
index 00000000..4967ec55
--- /dev/null
+++ b/variants/tenstar_c3/platformio.ini
@@ -0,0 +1,65 @@
+[Tenstar_esp32_C3]
+extends = esp32_base
+board = esp32-c3-devkitm-1
+build_flags =
+ ${esp32_base.build_flags}
+ -I variants/tenstar_c3
+ -D ESP32_CPU_FREQ=80
+ -D LORA_TX_BOOST_PIN=4
+ -D P_LORA_TX_NEOPIXEL_LED=10
+ -D PIN_VBAT_READ=1
+ -D P_LORA_MISO=9
+ -D P_LORA_SCLK=8
+ -D P_LORA_MOSI=7
+ -D P_LORA_DIO_1=2
+ -D P_LORA_NSS=6
+ -D P_LORA_RESET=RADIOLIB_NC
+ -D P_LORA_BUSY=3
+; -D PIN_BOARD_SDA=18
+; -D PIN_BOARD_SCL=19
+ -D SX126X_DIO2_AS_RF_SWITCH=true
+ -D SX126X_DIO3_TCXO_VOLTAGE=1.8
+ -D SX126X_CURRENT_LIMIT=140
+build_src_filter = ${esp32_base.build_src_filter}
+ +<../variants/tenstar_c3>
+
+[env:Tenstar_C3_Repeater_sx1262]
+extends = Tenstar_esp32_C3
+build_src_filter = ${Tenstar_esp32_C3.build_src_filter}
+ +<../examples/simple_repeater/main.cpp>
+build_flags =
+ ${Tenstar_esp32_C3.build_flags}
+ -D RADIO_CLASS=CustomSX1262
+ -D WRAPPER_CLASS=CustomSX1262Wrapper
+ -D SX126X_RX_BOOSTED_GAIN=1
+ -D LORA_TX_POWER=22
+ -D ADVERT_NAME='"Tenstar C3 Repeater"'
+ -D ADVERT_LAT=0.0
+ -D ADVERT_LON=0.0
+ -D ADMIN_PASSWORD='"password"'
+ -D MAX_NEIGHBOURS=8
+; -D MESH_PACKET_LOGGING=1
+; -D MESH_DEBUG=1
+lib_deps =
+ ${Tenstar_esp32_C3.lib_deps}
+ ${esp32_ota.lib_deps}
+
+[env:Tenstar_C3_Repeater_sx1268]
+extends = Tenstar_esp32_C3
+build_src_filter = ${Tenstar_esp32_C3.build_src_filter}
+ +<../examples/simple_repeater/main.cpp>
+build_flags =
+ ${Tenstar_esp32_C3.build_flags}
+ -D RADIO_CLASS=CustomSX1268
+ -D WRAPPER_CLASS=CustomSX1268Wrapper
+ -D LORA_TX_POWER=22
+ -D ADVERT_NAME='"Tenstar C3 Repeater"'
+ -D ADVERT_LAT=0.0
+ -D ADVERT_LON=0.0
+ -D ADMIN_PASSWORD='"password"'
+ -D MAX_NEIGHBOURS=8
+ ; -D MESH_PACKET_LOGGING=1
+ ; -D MESH_DEBUG=1
+lib_deps =
+ ${Tenstar_esp32_C3.lib_deps}
+ ${esp32_ota.lib_deps}
diff --git a/variants/tenstar_c3/target.cpp b/variants/tenstar_c3/target.cpp
new file mode 100644
index 00000000..a29780f0
--- /dev/null
+++ b/variants/tenstar_c3/target.cpp
@@ -0,0 +1,48 @@
+#include
+#include "target.h"
+
+XiaoC3Board 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);
+SensorManager sensors;
+
+bool radio_init() {
+ fallback_clock.begin();
+ rtc_clock.begin(Wire);
+
+#if defined(P_LORA_SCLK)
+ return radio.std_init(&spi);
+#else
+ return radio.std_init();
+#endif
+}
+
+uint32_t radio_get_rng_seed() {
+ return radio.random(0x7FFFFFFF);
+}
+
+void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
+ radio.setFrequency(freq);
+ radio.setSpreadingFactor(sf);
+ radio.setBandwidth(bw);
+ radio.setCodingRate(cr);
+}
+
+void radio_set_tx_power(uint8_t dbm) {
+ radio.setOutputPower(dbm);
+}
+
+mesh::LocalIdentity radio_new_identity() {
+ RadioNoiseListener rng(radio);
+ return mesh::LocalIdentity(&rng); // create new random identity
+}
diff --git a/variants/tenstar_c3/target.h b/variants/tenstar_c3/target.h
new file mode 100644
index 00000000..0aea87dd
--- /dev/null
+++ b/variants/tenstar_c3/target.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#define RADIOLIB_STATIC_ONLY 1
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern XiaoC3Board 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();
diff --git a/variants/wio-e5-dev/platformio.ini b/variants/wio-e5-dev/platformio.ini
index 22c2d880..ce96ad2a 100644
--- a/variants/wio-e5-dev/platformio.ini
+++ b/variants/wio-e5-dev/platformio.ini
@@ -7,6 +7,8 @@ build_flags = ${stm32_base.build_flags}
-D WRAPPER_CLASS=CustomSTM32WLxWrapper
-D SPI_INTERFACES_COUNT=0
-D RX_BOOSTED_GAIN=true
+ -D PIN_SERIAL_RX=PB7
+ -D PIN_SERIAL_TX=PB6
-I variants/wio-e5-dev
build_src_filter = ${stm32_base.build_src_filter}
+<../variants/wio-e5-dev>
diff --git a/variants/wio-e5-dev/variant.h b/variants/wio-e5-dev/variant.h
index 821fc410..ffd366f9 100644
--- a/variants/wio-e5-dev/variant.h
+++ b/variants/wio-e5-dev/variant.h
@@ -1,10 +1,5 @@
#pragma once
-// UART Definitions
-// #ifndef SERIAL_UART_INSTANCE
-// #define SERIAL_UART_INSTANCE 101
-// #endif
-
#include
#undef RNG