mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Merge branch 'dev' into double-acks
This commit is contained in:
commit
f7920114c5
39 changed files with 775 additions and 241 deletions
79
docs/faq.md
79
docs/faq.md
|
|
@ -64,9 +64,13 @@ author: https://github.com/LitBomb<!-- omit from toc -->
|
|||
- [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 <https://www.epochconverter.com/> 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 <https://www.epochconverter.com/> 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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
54
docs/packet_structure.md
Normal file
54
docs/packet_structure.md
Normal file
|
|
@ -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. |
|
||||
|
|
@ -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 `<sender name>: <message body>` (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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: ");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: ");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#if defined(TBEAM_SUPREME_SX1262) || defined(TBEAM_SX1262) || defined(TBEAM_SX1276)
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "TBeamBoard.h"
|
||||
//#include <RadioLib.h>
|
||||
|
|
@ -343,4 +345,6 @@ bool TBeamBoard::power_init()
|
|||
|
||||
|
||||
// }
|
||||
#pragma endregion
|
||||
#pragma endregion
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(TBEAM_SUPREME_SX1262) || defined(TBEAM_SX1262) || defined(TBEAM_SX1276)
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Arduino.h>
|
||||
#include "XPowersLib.h"
|
||||
|
|
@ -162,3 +164,5 @@ public:
|
|||
return "LilyGo T-Beam";
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <Adafruit_BMP280.h>
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
+<helpers/sensors>
|
||||
+<helpers/sensors>
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
+<helpers/sensors>
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <helpers/CustomSX1276Wrapper.h>
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <helpers/SensorManager.h>
|
||||
#include <helpers/sensors/EnvironmentSensorManager.h>
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include <helpers/ui/SSD1306Display.h>
|
||||
#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;
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
+<helpers/nrf52/PromicroBoard.cpp>
|
||||
+<helpers/sensors>
|
||||
+<helpers/sensors>
|
||||
+<../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}
|
||||
+<helpers/nrf52/PromicroBoard.cpp>
|
||||
+<helpers/sensors>
|
||||
+<helpers/sensors>
|
||||
+<../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
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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: ");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
|||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../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}
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../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]
|
||||
|
|
|
|||
|
|
@ -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 <bsec2.h>
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
+<helpers/ui/SH1106Display.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() {
|
||||
|
|
|
|||
65
variants/tenstar_c3/platformio.ini
Normal file
65
variants/tenstar_c3/platformio.ini
Normal file
|
|
@ -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}
|
||||
48
variants/tenstar_c3/target.cpp
Normal file
48
variants/tenstar_c3/target.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include <Arduino.h>
|
||||
#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
|
||||
}
|
||||
21
variants/tenstar_c3/target.h
Normal file
21
variants/tenstar_c3/target.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#define RADIOLIB_STATIC_ONLY 1
|
||||
#include <RadioLib.h>
|
||||
#include <helpers/RadioLibWrappers.h>
|
||||
#include <helpers/XiaoC3Board.h>
|
||||
#include <helpers/CustomSX1262Wrapper.h>
|
||||
#include <helpers/CustomSX1268Wrapper.h>
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <helpers/SensorManager.h>
|
||||
|
||||
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();
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
// UART Definitions
|
||||
// #ifndef SERIAL_UART_INSTANCE
|
||||
// #define SERIAL_UART_INSTANCE 101
|
||||
// #endif
|
||||
|
||||
#include <variant_generic.h>
|
||||
|
||||
#undef RNG
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue