mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-07-02 06:11:36 +00:00
Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| affe61dc3b | |||
| 4f701b7aec | |||
| dd87371574 | |||
| 4f7c1cb88f | |||
| 1869b57d62 | |||
| 58b0f7df9c | |||
| bc35208682 | |||
| 4f8cb8db78 | |||
| 5ff39c6243 | |||
| dc200cf22d | |||
| 62b95b4e48 | |||
| f3d4d8cd5e | |||
| 3d4eec4a6a | |||
| b07aba7937 | |||
| 1f9bb67400 | |||
| b8f1fad654 | |||
| eb938a9b78 | |||
| 69df5c7a95 | |||
| 9c7d71b9be | |||
| 5d0ff7fe6e | |||
| 3192684582 | |||
| aa1cb1f663 | |||
| 6a63dfce1c | |||
| c2cfba4af3 | |||
| 62849ef114 | |||
| 60ea4a91bf | |||
| dd9b3b32c3 | |||
| 7c8e092457 | |||
| 099ef67348 | |||
| 04a6c7009a | |||
| 813d108c7a | |||
| 4f9a091671 | |||
| e7db7c5a94 | |||
| 29f0a7fc4f | |||
| 2e73fe948e | |||
| 538ac38e18 | |||
| c2d223ff55 | |||
| 07648e3344 | |||
| a5cb0c25ca | |||
| 5300fa18c7 | |||
| 3ee58fd2e3 | |||
| d5f74e93c5 | |||
| 1c4c995a41 | |||
| d2d3d44c9b | |||
| fe56d01da2 | |||
| 190dbb5293 | |||
| 9100a58671 | |||
| 5f3b7f25d0 | |||
| ae0bb7ee95 | |||
| 07bfe90695 | |||
| 07a3ca9e05 | |||
| 8c0d5c5b24 | |||
| 74adda6316 | |||
| b6454d6251 | |||
| 6a9a84e8a5 | |||
| add18d6866 | |||
| 4bf391f5c3 | |||
| c67548347c | |||
| bbd37f53a8 | |||
| 00d445a269 | |||
| 250f448c3f | |||
| c940ea5f30 | |||
| f29cae602f | |||
| d4c99dec65 | |||
| 181a54e718 | |||
| 910b1bee5b | |||
| 16cb6d518f | |||
| 3a546a6395 | |||
| 09a27a2591 | |||
| 12e6899580 | |||
| 1a7b3614a8 | |||
| 444dcfb8fd | |||
| 03a13aed30 | |||
| fed8d36d03 | |||
| b948369d71 | |||
| 34db93150a | |||
| 528bf3f61e | |||
| 62b0d82682 | |||
| 9d26953398 | |||
| c42f6db0eb | |||
| 22f07b3e48 | |||
| ca047fe0c0 | |||
| ddedb3c7a7 | |||
| 68360157ec | |||
| 9664305a87 | |||
| 2442e9a5bd | |||
| 65752fef72 | |||
| 8435464c84 |
@@ -0,0 +1 @@
|
|||||||
|
github: meshcore-dev
|
||||||
@@ -4,7 +4,7 @@ runs:
|
|||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Init Cache
|
- name: Init Cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/pip
|
~/.cache/pip
|
||||||
@@ -12,9 +12,9 @@ runs:
|
|||||||
key: ${{ runner.os }}-pio
|
key: ${{ runner.os }}-pio
|
||||||
|
|
||||||
- name: Install Python
|
- name: Install Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: '3.11'
|
python-version: '3.13'
|
||||||
|
|
||||||
- name: Install PlatformIO
|
- name: Install PlatformIO
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Clone Repo
|
- name: Clone Repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup Build Environment
|
- name: Setup Build Environment
|
||||||
uses: ./.github/actions/setup-build-environment
|
uses: ./.github/actions/setup-build-environment
|
||||||
@@ -27,13 +27,13 @@ jobs:
|
|||||||
run: /usr/bin/env bash build.sh build-companion-firmwares
|
run: /usr/bin/env bash build.sh build-companion-firmwares
|
||||||
|
|
||||||
- name: Upload Workflow Artifacts
|
- name: Upload Workflow Artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: companion-firmwares
|
name: companion-firmwares
|
||||||
path: out
|
path: out
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v3
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
name: Companion Firmware ${{ env.GIT_TAG_VERSION }}
|
name: Companion Firmware ${{ env.GIT_TAG_VERSION }}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Clone Repo
|
- name: Clone Repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup Build Environment
|
- name: Setup Build Environment
|
||||||
uses: ./.github/actions/setup-build-environment
|
uses: ./.github/actions/setup-build-environment
|
||||||
@@ -27,13 +27,13 @@ jobs:
|
|||||||
run: /usr/bin/env bash build.sh build-repeater-firmwares
|
run: /usr/bin/env bash build.sh build-repeater-firmwares
|
||||||
|
|
||||||
- name: Upload Workflow Artifacts
|
- name: Upload Workflow Artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: repeater-firmwares
|
name: repeater-firmwares
|
||||||
path: out
|
path: out
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v3
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
name: Repeater Firmware ${{ env.GIT_TAG_VERSION }}
|
name: Repeater Firmware ${{ env.GIT_TAG_VERSION }}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Clone Repo
|
- name: Clone Repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup Build Environment
|
- name: Setup Build Environment
|
||||||
uses: ./.github/actions/setup-build-environment
|
uses: ./.github/actions/setup-build-environment
|
||||||
@@ -27,13 +27,13 @@ jobs:
|
|||||||
run: /usr/bin/env bash build.sh build-room-server-firmwares
|
run: /usr/bin/env bash build.sh build-room-server-firmwares
|
||||||
|
|
||||||
- name: Upload Workflow Artifacts
|
- name: Upload Workflow Artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: room-server-firmwares
|
name: room-server-firmwares
|
||||||
path: out
|
path: out
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v3
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
name: Room Server Firmware ${{ env.GIT_TAG_VERSION }}
|
name: Room Server Firmware ${{ env.GIT_TAG_VERSION }}
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.x
|
python-version: '3.13'
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
mkdocs build
|
mkdocs build
|
||||||
|
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v4.1.0
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
cname: docs.meshcore.io
|
cname: docs.meshcore.io
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone Repo
|
- name: Clone Repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup Build Environment
|
- name: Setup Build Environment
|
||||||
uses: ./.github/actions/setup-build-environment
|
uses: ./.github/actions/setup-build-environment
|
||||||
|
|||||||
Vendored
+1
-2
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
|
||||||
// for the documentation about the extensions.json format
|
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
|
"pioarduino.pioarduino-ide",
|
||||||
"platformio.platformio-ide"
|
"platformio.platformio-ide"
|
||||||
],
|
],
|
||||||
"unwantedRecommendations": [
|
"unwantedRecommendations": [
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ MeshCore provides the ability to create wireless mesh networks, similar to Mesht
|
|||||||
|
|
||||||
## 🚀 How to Get Started
|
## 🚀 How to Get Started
|
||||||
|
|
||||||
- Watch the [MeshCore Intro Video](https://www.youtube.com/watch?v=t1qne8uJBAc) by Andy Kirby.
|
- Watch the [MeshCore QuickStart Playlist](https://www.youtube.com/watch?v=iaFltojJrAc&list=PLshzThxhw4O4WU_iZo3NmNZOv6KMrUuF9) by The Comms Channel
|
||||||
- Watch the [MeshCore Technical Presentation](https://www.youtube.com/watch?v=OwmkVkZQTf4) by Liam Cottle.
|
- Watch the [MeshCore Technical Presentation](https://www.youtube.com/watch?v=OwmkVkZQTf4) by Liam Cottle.
|
||||||
- Read through our [Frequently Asked Questions](./docs/faq.md) and [Documentation](https://docs.meshcore.io).
|
- Read through our [Frequently Asked Questions](./docs/faq.md) and [Documentation](https://docs.meshcore.io).
|
||||||
- Flash the MeshCore firmware on a supported device.
|
- Flash the MeshCore firmware on a supported device.
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "nrf52840_s140_v6.ld"
|
||||||
|
},
|
||||||
|
"core": "nRF5",
|
||||||
|
"cpu": "cortex-m4",
|
||||||
|
"extra_flags": "-DNRF52840_XXAA",
|
||||||
|
"f_cpu": "64000000L",
|
||||||
|
"hwids": [
|
||||||
|
["0x239A","0x4405"],
|
||||||
|
["0x239A","0x0029"],
|
||||||
|
["0x239A","0x002A"],
|
||||||
|
["0x239A","0x0071"]
|
||||||
|
],
|
||||||
|
"usb_product": "HT-n5262",
|
||||||
|
"mcu": "nrf52840",
|
||||||
|
"variant": "heltec_tower_v2",
|
||||||
|
"bsp": {
|
||||||
|
"name": "adafruit"
|
||||||
|
},
|
||||||
|
"softdevice": {
|
||||||
|
"sd_flags": "-DS140",
|
||||||
|
"sd_name": "s140",
|
||||||
|
"sd_version": "6.1.1",
|
||||||
|
"sd_fwid": "0x00B6"
|
||||||
|
},
|
||||||
|
"bootloader": {
|
||||||
|
"settings_addr": "0xFF000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"bluetooth"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"jlink_device": "nRF52840_xxAA",
|
||||||
|
"svd_path": "nrf52840.svd",
|
||||||
|
"openocd_target": "nrf52.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino"
|
||||||
|
],
|
||||||
|
"name": "Heltec Tower V2 Board",
|
||||||
|
"upload": {
|
||||||
|
"maximum_ram_size": 235520,
|
||||||
|
"maximum_size": 815104,
|
||||||
|
"speed": 115200,
|
||||||
|
"protocol": "nrfutil",
|
||||||
|
"protocols": [
|
||||||
|
"jlink",
|
||||||
|
"nrfjprog",
|
||||||
|
"nrfutil",
|
||||||
|
"stlink"
|
||||||
|
],
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"wait_for_upload_port": true
|
||||||
|
},
|
||||||
|
"url": "https://heltec.org/",
|
||||||
|
"vendor": "Heltec"
|
||||||
|
}
|
||||||
+4
-3
@@ -1,11 +1,12 @@
|
|||||||
{ pkgs ? import <nixpkgs> {} }:
|
{pkgs ? import <nixpkgs> {}}: let
|
||||||
let
|
|
||||||
in
|
in
|
||||||
pkgs.mkShell {
|
pkgs.mkShell {
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
pkgs.platformio
|
pkgs.platformio
|
||||||
pkgs.python3
|
pkgs.python3
|
||||||
|
pkgs.gcc
|
||||||
|
pkgs.gtest
|
||||||
# optional: needed as a programmer i.e. for esp32
|
# optional: needed as a programmer i.e. for esp32
|
||||||
pkgs.avrdude
|
pkgs.avrdude
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-1
@@ -263,6 +263,20 @@ This document provides an overview of CLI commands that can be sent to MeshCore
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### View or change the LoRa FEM receive-path gain state on supported boards
|
||||||
|
**Usage:**
|
||||||
|
- `get radio.fem.rxgain`
|
||||||
|
- `set radio.fem.rxgain <state>`
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `state`: `on`|`off`
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
- This controls the external LoRa FEM receive-path LNA where the board supports it.
|
||||||
|
- This is separate from `radio.rxgain`, which controls the radio chip receive gain mode.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### System
|
### System
|
||||||
|
|
||||||
#### View or change this node's name
|
#### View or change this node's name
|
||||||
@@ -391,6 +405,11 @@ This document provides an overview of CLI commands that can be sent to MeshCore
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### View this node's firmware version
|
||||||
|
**Usage:** `ver`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
#### View this node's configured role
|
#### View this node's configured role
|
||||||
**Usage:** `get role`
|
**Usage:** `get role`
|
||||||
|
|
||||||
@@ -406,7 +425,7 @@ This document provides an overview of CLI commands that can be sent to MeshCore
|
|||||||
- `on`: enable power saving
|
- `on`: enable power saving
|
||||||
- `off`: disable power saving
|
- `off`: disable power saving
|
||||||
|
|
||||||
**Default:** `on`
|
**Default:** `off`
|
||||||
|
|
||||||
**Note:** When enabled, device enters sleep mode between radio transmissions
|
**Note:** When enabled, device enters sleep mode between radio transmissions
|
||||||
|
|
||||||
@@ -559,6 +578,20 @@ This document provides an overview of CLI commands that can be sent to MeshCore
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### Enable or disable hardware Channel Activity Detection (CAD)
|
||||||
|
**Usage:**
|
||||||
|
- `get cad`
|
||||||
|
- `set cad <on|off>`
|
||||||
|
|
||||||
|
**Description:** When enabled, the radio performs a hardware Channel Activity Detection scan before transmitting and defers if the channel is busy. Runs independently of `int.thresh` — either, both, or none may be active.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `on|off`: Enable or disable hardware CAD
|
||||||
|
|
||||||
|
**Default:** `off`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
#### View or change the AGC Reset Interval
|
#### View or change the AGC Reset Interval
|
||||||
**Usage:**
|
**Usage:**
|
||||||
- `get agc.reset.interval`
|
- `get agc.reset.interval`
|
||||||
|
|||||||
+1
-9
@@ -111,7 +111,6 @@ Anyone is able to build anything they like on top of MeshCore without paying any
|
|||||||
- MeshCore Firmware on GitHub: [https://github.com/meshcore-dev/MeshCore](https://github.com/meshcore-dev/MeshCore)
|
- MeshCore Firmware on GitHub: [https://github.com/meshcore-dev/MeshCore](https://github.com/meshcore-dev/MeshCore)
|
||||||
- MeshCore Companion Web App: [https://app.meshcore.nz](https://app.meshcore.nz)
|
- MeshCore Companion Web App: [https://app.meshcore.nz](https://app.meshcore.nz)
|
||||||
- MeshCore Map: [https://map.meshcore.io](https://map.meshcore.io)
|
- MeshCore Map: [https://map.meshcore.io](https://map.meshcore.io)
|
||||||
- Andy Kirby's [MeshCore Intro Video](https://www.youtube.com/watch?v=t1qne8uJBAc)
|
|
||||||
- Liam Cottle's [MeshCore Technical Presentation](https://www.youtube.com/watch?v=OwmkVkZQTf4)
|
- Liam Cottle's [MeshCore Technical Presentation](https://www.youtube.com/watch?v=OwmkVkZQTf4)
|
||||||
|
|
||||||
You need LoRa hardware devices to run MeshCore firmware as clients or server (repeater and room server).
|
You need LoRa hardware devices to run MeshCore firmware as clients or server (repeater and room server).
|
||||||
@@ -392,10 +391,7 @@ Another way to download map tiles is to use this Python script to get the tiles
|
|||||||
<https://github.com/fistulareffigy/MTD-Script>
|
<https://github.com/fistulareffigy/MTD-Script>
|
||||||
|
|
||||||
There is also a modified script that adds additional error handling and parallel downloads:
|
There is also a modified script that adds additional error handling and parallel downloads:
|
||||||
<https://discord.com/channels/826570251612323860/1330643963501351004/1338775811548905572>
|
<https://github.com/TheBestJohn/MTD-Script>
|
||||||
|
|
||||||
UK map tiles are available separately from Andy Kirby on his discord server:
|
|
||||||
<https://discord.com/channels/826570251612323860/1330643963501351004/1331346597367386224>
|
|
||||||
|
|
||||||
### 4.8. Q: Where do the map tiles go?
|
### 4.8. Q: Where do the map tiles go?
|
||||||
Once you have the tiles downloaded, copy the `\tiles` folder to the root of your T-Deck's SD card.
|
Once you have the tiles downloaded, copy the `\tiles` folder to the root of your T-Deck's SD card.
|
||||||
@@ -553,10 +549,6 @@ pio run -e RAK_4631_Repeater
|
|||||||
```
|
```
|
||||||
then you'll find `firmware.zip` in `.pio/build/RAK_4631_Repeater`
|
then you'll find `firmware.zip` in `.pio/build/RAK_4631_Repeater`
|
||||||
|
|
||||||
Andy also has a video on how to build using VS Code:
|
|
||||||
*How to build and flash Meshcore repeater firmware | Heltec V3*
|
|
||||||
<https://www.youtube.com/watch?v=WJvg6dt13hk> *(Link referenced in the Discord post)*
|
|
||||||
|
|
||||||
### 5.10. Q: Are there other MeshCore related open source projects?
|
### 5.10. Q: Are there other MeshCore related open source projects?
|
||||||
|
|
||||||
**A:** [Liam Cottle](https://liamcottle.net)'s MeshCore web client and MeshCore JavaScript library are open source under MIT license.
|
**A:** [Liam Cottle](https://liamcottle.net)'s MeshCore web client and MeshCore JavaScript library are open source under MIT license.
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ Once you have a working app/project, you need to be able to demonstrate it exist
|
|||||||
| 0000 - 00FF | -reserved for internal use- | |
|
| 0000 - 00FF | -reserved for internal use- | |
|
||||||
| 0100 | MeshCore Open | zsylvester@monitormx.com — https://github.com/zjs81/meshcore-open |
|
| 0100 | MeshCore Open | zsylvester@monitormx.com — https://github.com/zjs81/meshcore-open |
|
||||||
| 0110 - 011F | Ripple | ripple_biz@protonmail.com — https://buymeacoffee.com/ripplebiz |
|
| 0110 - 011F | Ripple | ripple_biz@protonmail.com — https://buymeacoffee.com/ripplebiz |
|
||||||
|
| 0120 | MCO Advanced | most.original.address@gmail.com — https://hdden.ru/MCOa/ |
|
||||||
| FF00 - FFFF | -reserved for testing/dev- | |
|
| FF00 - FFFF | -reserved for testing/dev- | |
|
||||||
|
|
||||||
(add rows, inside the range 0100 - FEFF for custom apps)
|
(add rows, inside the range 0100 - FEFF for custom apps)
|
||||||
|
|||||||
@@ -545,7 +545,7 @@ bool DataStore::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src
|
|||||||
uint32_t pos = 0, found_pos = 0;
|
uint32_t pos = 0, found_pos = 0;
|
||||||
uint32_t min_timestamp = 0xFFFFFFFF;
|
uint32_t min_timestamp = 0xFFFFFFFF;
|
||||||
|
|
||||||
// search for matching key OR evict by oldest timestmap
|
// search for matching key OR evict by oldest timestamp
|
||||||
BlobRec tmp;
|
BlobRec tmp;
|
||||||
file.seek(0);
|
file.seek(0);
|
||||||
while (file.read((uint8_t *) &tmp, sizeof(tmp)) == sizeof(tmp)) {
|
while (file.read((uint8_t *) &tmp, sizeof(tmp)) == sizeof(tmp)) {
|
||||||
|
|||||||
@@ -261,6 +261,9 @@ float MyMesh::getAirtimeBudgetFactor() const {
|
|||||||
int MyMesh::getInterferenceThreshold() const {
|
int MyMesh::getInterferenceThreshold() const {
|
||||||
return 0; // disabled for now, until currentRSSI() problem is resolved
|
return 0; // disabled for now, until currentRSSI() problem is resolved
|
||||||
}
|
}
|
||||||
|
bool MyMesh::getCADEnabled() const {
|
||||||
|
return true; // hardware CAD before TX (no CLI toggle on companion; enabled by default)
|
||||||
|
}
|
||||||
|
|
||||||
int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
|
int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
|
||||||
if (_prefs.rx_delay_base <= 0.0f) return 0;
|
if (_prefs.rx_delay_base <= 0.0f) return 0;
|
||||||
@@ -854,7 +857,7 @@ void MyMesh::onSendTimeout() {}
|
|||||||
|
|
||||||
MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store, AbstractUITask* ui)
|
MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store, AbstractUITask* ui)
|
||||||
: BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables),
|
: BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables),
|
||||||
_serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4), _store(&store), _ui(ui) {
|
_serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4), _store(&store), _ui(ui), _iter(0) {
|
||||||
_iter_started = false;
|
_iter_started = false;
|
||||||
_cli_rescue = false;
|
_cli_rescue = false;
|
||||||
offline_queue_len = 0;
|
offline_queue_len = 0;
|
||||||
@@ -1542,6 +1545,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
|||||||
memcpy(anon.id.pub_key, pub_key, PUB_KEY_SIZE);
|
memcpy(anon.id.pub_key, pub_key, PUB_KEY_SIZE);
|
||||||
anon.out_path_len = 0; // default to zero-hop direct
|
anon.out_path_len = 0; // default to zero-hop direct
|
||||||
anon.type = ADV_TYPE_NONE; // unknown
|
anon.type = ADV_TYPE_NONE; // unknown
|
||||||
|
anon.lastmod = getRTCClock()->getCurrentTime();
|
||||||
|
|
||||||
if (addContact(anon)) recipient = &anon;
|
if (addContact(anon)) recipient = &anon;
|
||||||
}
|
}
|
||||||
@@ -1981,6 +1985,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
|||||||
sendPacket(pkt, priority, 0);
|
sendPacket(pkt, priority, 0);
|
||||||
writeOKFrame();
|
writeOKFrame();
|
||||||
} else {
|
} else {
|
||||||
|
releasePacket(pkt);
|
||||||
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
|
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -2186,15 +2191,7 @@ void MyMesh::checkSerialInterface() {
|
|||||||
&& !_serial->isWriteBusy() // don't spam the Serial Interface too quickly!
|
&& !_serial->isWriteBusy() // don't spam the Serial Interface too quickly!
|
||||||
) {
|
) {
|
||||||
ContactInfo contact;
|
ContactInfo contact;
|
||||||
bool found = false;
|
if (_iter.hasNext(this, contact)) {
|
||||||
while (_iter.hasNext(this, contact)) {
|
|
||||||
if (contact.type != ADV_TYPE_NONE) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
if (contact.lastmod > _iter_filter_since) { // apply the 'since' filter
|
if (contact.lastmod > _iter_filter_since) { // apply the 'since' filter
|
||||||
writeContactRespFrame(RESP_CODE_CONTACT, contact);
|
writeContactRespFrame(RESP_CODE_CONTACT, contact);
|
||||||
if (contact.lastmod > _most_recent_lastmod) {
|
if (contact.lastmod > _most_recent_lastmod) {
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
#define FIRMWARE_VER_CODE 13
|
#define FIRMWARE_VER_CODE 13
|
||||||
|
|
||||||
#ifndef FIRMWARE_BUILD_DATE
|
#ifndef FIRMWARE_BUILD_DATE
|
||||||
#define FIRMWARE_BUILD_DATE "19 Apr 2026"
|
#define FIRMWARE_BUILD_DATE "6 Jun 2026"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FIRMWARE_VERSION
|
#ifndef FIRMWARE_VERSION
|
||||||
#define FIRMWARE_VERSION "v1.15.0"
|
#define FIRMWARE_VERSION "v1.16.0"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||||
@@ -105,6 +105,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
float getAirtimeBudgetFactor() const override;
|
float getAirtimeBudgetFactor() const override;
|
||||||
int getInterferenceThreshold() const override;
|
int getInterferenceThreshold() const override;
|
||||||
|
bool getCADEnabled() const override;
|
||||||
int calcRxDelay(float score, uint32_t air_time) const override;
|
int calcRxDelay(float score, uint32_t air_time) const override;
|
||||||
uint32_t getRetransmitDelay(const mesh::Packet *packet) override;
|
uint32_t getRetransmitDelay(const mesh::Packet *packet) override;
|
||||||
uint32_t getDirectRetransmitDelay(const mesh::Packet *packet) override;
|
uint32_t getDirectRetransmitDelay(const mesh::Packet *packet) override;
|
||||||
|
|||||||
@@ -893,6 +893,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
|||||||
_prefs.flood_max_unscoped = 64;
|
_prefs.flood_max_unscoped = 64;
|
||||||
_prefs.flood_max_advert = 8;
|
_prefs.flood_max_advert = 8;
|
||||||
_prefs.interference_threshold = 0; // disabled
|
_prefs.interference_threshold = 0; // disabled
|
||||||
|
_prefs.cad_enabled = 0; // hardware CAD before TX (off by default; 'set cad on')
|
||||||
|
|
||||||
// bridge defaults
|
// bridge defaults
|
||||||
_prefs.bridge_enabled = 1; // enabled
|
_prefs.bridge_enabled = 1; // enabled
|
||||||
@@ -917,6 +918,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
|||||||
_prefs.rx_boosted_gain = 1; // enabled by default;
|
_prefs.rx_boosted_gain = 1; // enabled by default;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
_prefs.radio_fem_rxgain = 1;
|
||||||
|
|
||||||
pending_discover_tag = 0;
|
pending_discover_tag = 0;
|
||||||
pending_discover_until = 0;
|
pending_discover_until = 0;
|
||||||
@@ -965,6 +967,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
|
|||||||
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
|
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
|
||||||
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
|
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
|
||||||
radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled");
|
radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled");
|
||||||
|
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
|
||||||
|
|
||||||
updateAdvertTimer();
|
updateAdvertTimer();
|
||||||
updateFloodAdvertTimer();
|
updateFloodAdvertTimer();
|
||||||
@@ -1059,11 +1062,9 @@ void MyMesh::setTxPower(int8_t power_dbm) {
|
|||||||
radio_driver.setTxPower(power_dbm);
|
radio_driver.setTxPower(power_dbm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_SX1262) || defined(USE_SX1268)
|
bool MyMesh::setRxBoostedGain(bool enable) {
|
||||||
void MyMesh::setRxBoostedGain(bool enable) {
|
return radio_driver.setRxBoostedGainMode(enable);
|
||||||
radio_driver.setRxBoostedGainMode(enable);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void MyMesh::formatNeighborsReply(char *reply) {
|
void MyMesh::formatNeighborsReply(char *reply) {
|
||||||
char *dp = reply;
|
char *dp = reply;
|
||||||
|
|||||||
@@ -69,11 +69,11 @@ struct NeighbourInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifndef FIRMWARE_BUILD_DATE
|
#ifndef FIRMWARE_BUILD_DATE
|
||||||
#define FIRMWARE_BUILD_DATE "19 Apr 2026"
|
#define FIRMWARE_BUILD_DATE "6 Jun 2026"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FIRMWARE_VERSION
|
#ifndef FIRMWARE_VERSION
|
||||||
#define FIRMWARE_VERSION "v1.15.0"
|
#define FIRMWARE_VERSION "v1.16.0"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FIRMWARE_ROLE "repeater"
|
#define FIRMWARE_ROLE "repeater"
|
||||||
@@ -150,6 +150,9 @@ protected:
|
|||||||
int getInterferenceThreshold() const override {
|
int getInterferenceThreshold() const override {
|
||||||
return _prefs.interference_threshold;
|
return _prefs.interference_threshold;
|
||||||
}
|
}
|
||||||
|
bool getCADEnabled() const override {
|
||||||
|
return _prefs.cad_enabled;
|
||||||
|
}
|
||||||
int getAGCResetInterval() const override {
|
int getAGCResetInterval() const override {
|
||||||
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
|
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
|
||||||
}
|
}
|
||||||
@@ -249,7 +252,6 @@ public:
|
|||||||
// To check if there is pending work
|
// To check if there is pending work
|
||||||
bool hasPendingWork() const;
|
bool hasPendingWork() const;
|
||||||
|
|
||||||
#if defined(USE_SX1262) || defined(USE_SX1268)
|
bool setRxBoostedGain(bool enable) override;
|
||||||
void setRxBoostedGain(bool enable) override;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// v1.2.3 (1 Jan 2025)
|
// v1.2.3 (1 Jan 2025)
|
||||||
sprintf(_version_info, "%s (%s)", version, build_date);
|
snprintf(_version_info, sizeof(_version_info), "%s (%s)", version, build_date);
|
||||||
|
free(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::renderCurrScreen() {
|
void UITask::renderCurrScreen() {
|
||||||
|
|||||||
@@ -650,6 +650,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
|||||||
_prefs.flood_max_unscoped = 64;
|
_prefs.flood_max_unscoped = 64;
|
||||||
_prefs.flood_max_advert = 8;
|
_prefs.flood_max_advert = 8;
|
||||||
_prefs.interference_threshold = 0; // disabled
|
_prefs.interference_threshold = 0; // disabled
|
||||||
|
_prefs.cad_enabled = 0; // hardware CAD before TX (off by default; 'set cad on')
|
||||||
#ifdef ROOM_PASSWORD
|
#ifdef ROOM_PASSWORD
|
||||||
StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password));
|
StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password));
|
||||||
#endif
|
#endif
|
||||||
@@ -658,6 +659,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
|||||||
_prefs.gps_enabled = 0;
|
_prefs.gps_enabled = 0;
|
||||||
_prefs.gps_interval = 0;
|
_prefs.gps_interval = 0;
|
||||||
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
|
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
|
||||||
|
_prefs.radio_fem_rxgain = 1;
|
||||||
|
|
||||||
next_post_idx = 0;
|
next_post_idx = 0;
|
||||||
next_client_idx = 0;
|
next_client_idx = 0;
|
||||||
@@ -699,6 +701,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
|
|||||||
|
|
||||||
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
|
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
|
||||||
radio_driver.setTxPower(_prefs.tx_power_dbm);
|
radio_driver.setTxPower(_prefs.tx_power_dbm);
|
||||||
|
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
|
||||||
|
|
||||||
updateAdvertTimer();
|
updateAdvertTimer();
|
||||||
updateFloodAdvertTimer();
|
updateFloodAdvertTimer();
|
||||||
|
|||||||
@@ -27,11 +27,11 @@
|
|||||||
/* ------------------------------ Config -------------------------------- */
|
/* ------------------------------ Config -------------------------------- */
|
||||||
|
|
||||||
#ifndef FIRMWARE_BUILD_DATE
|
#ifndef FIRMWARE_BUILD_DATE
|
||||||
#define FIRMWARE_BUILD_DATE "19 Apr 2026"
|
#define FIRMWARE_BUILD_DATE "6 Jun 2026"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FIRMWARE_VERSION
|
#ifndef FIRMWARE_VERSION
|
||||||
#define FIRMWARE_VERSION "v1.15.0"
|
#define FIRMWARE_VERSION "v1.16.0"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LORA_FREQ
|
#ifndef LORA_FREQ
|
||||||
@@ -144,6 +144,9 @@ protected:
|
|||||||
int getInterferenceThreshold() const override {
|
int getInterferenceThreshold() const override {
|
||||||
return _prefs.interference_threshold;
|
return _prefs.interference_threshold;
|
||||||
}
|
}
|
||||||
|
bool getCADEnabled() const override {
|
||||||
|
return _prefs.cad_enabled;
|
||||||
|
}
|
||||||
int getAGCResetInterval() const override {
|
int getAGCResetInterval() const override {
|
||||||
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
|
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// v1.2.3 (1 Jan 2025)
|
// v1.2.3 (1 Jan 2025)
|
||||||
sprintf(_version_info, "%s (%s)", version, build_date);
|
snprintf(_version_info, sizeof(_version_info), "%s (%s)", version, build_date);
|
||||||
|
free(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::renderCurrScreen() {
|
void UITask::renderCurrScreen() {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ class MyMesh : public BaseChatMesh, ContactVisitor {
|
|||||||
File file = _fs->open("/contacts", "w", true);
|
File file = _fs->open("/contacts", "w", true);
|
||||||
#endif
|
#endif
|
||||||
if (file) {
|
if (file) {
|
||||||
ContactsIterator iter;
|
ContactsIterator iter = startContactsIterator();
|
||||||
ContactInfo c;
|
ContactInfo c;
|
||||||
uint8_t unused = 0;
|
uint8_t unused = 0;
|
||||||
uint32_t reserved = 0;
|
uint32_t reserved = 0;
|
||||||
|
|||||||
@@ -323,6 +323,9 @@ uint32_t SensorMesh::getDirectRetransmitDelay(const mesh::Packet* packet) {
|
|||||||
int SensorMesh::getInterferenceThreshold() const {
|
int SensorMesh::getInterferenceThreshold() const {
|
||||||
return _prefs.interference_threshold;
|
return _prefs.interference_threshold;
|
||||||
}
|
}
|
||||||
|
bool SensorMesh::getCADEnabled() const {
|
||||||
|
return _prefs.cad_enabled;
|
||||||
|
}
|
||||||
int SensorMesh::getAGCResetInterval() const {
|
int SensorMesh::getAGCResetInterval() const {
|
||||||
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
|
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
|
||||||
}
|
}
|
||||||
@@ -726,11 +729,13 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise
|
|||||||
_prefs.disable_fwd = true;
|
_prefs.disable_fwd = true;
|
||||||
_prefs.flood_max = 64;
|
_prefs.flood_max = 64;
|
||||||
_prefs.interference_threshold = 0; // disabled
|
_prefs.interference_threshold = 0; // disabled
|
||||||
|
_prefs.cad_enabled = 0; // hardware CAD before TX (off by default; 'set cad on')
|
||||||
|
|
||||||
// GPS defaults
|
// GPS defaults
|
||||||
_prefs.gps_enabled = 0;
|
_prefs.gps_enabled = 0;
|
||||||
_prefs.gps_interval = 0;
|
_prefs.gps_interval = 0;
|
||||||
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
|
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
|
||||||
|
_prefs.radio_fem_rxgain = 1;
|
||||||
|
|
||||||
memset(default_scope.key, 0, sizeof(default_scope.key));
|
memset(default_scope.key, 0, sizeof(default_scope.key));
|
||||||
}
|
}
|
||||||
@@ -766,6 +771,7 @@ void SensorMesh::begin(FILESYSTEM* fs) {
|
|||||||
|
|
||||||
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
|
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
|
||||||
radio_driver.setTxPower(_prefs.tx_power_dbm);
|
radio_driver.setTxPower(_prefs.tx_power_dbm);
|
||||||
|
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
|
||||||
|
|
||||||
updateAdvertTimer();
|
updateAdvertTimer();
|
||||||
updateFloodAdvertTimer();
|
updateFloodAdvertTimer();
|
||||||
|
|||||||
@@ -34,11 +34,11 @@
|
|||||||
#define PERM_RECV_ALERTS_HI (1 << 7) // high priority alerts
|
#define PERM_RECV_ALERTS_HI (1 << 7) // high priority alerts
|
||||||
|
|
||||||
#ifndef FIRMWARE_BUILD_DATE
|
#ifndef FIRMWARE_BUILD_DATE
|
||||||
#define FIRMWARE_BUILD_DATE "19 Apr 2026"
|
#define FIRMWARE_BUILD_DATE "6 Jun 2026"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FIRMWARE_VERSION
|
#ifndef FIRMWARE_VERSION
|
||||||
#define FIRMWARE_VERSION "v1.15.0"
|
#define FIRMWARE_VERSION "v1.16.0"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FIRMWARE_ROLE "sensor"
|
#define FIRMWARE_ROLE "sensor"
|
||||||
@@ -120,6 +120,7 @@ protected:
|
|||||||
uint32_t getRetransmitDelay(const mesh::Packet* packet) override;
|
uint32_t getRetransmitDelay(const mesh::Packet* packet) override;
|
||||||
uint32_t getDirectRetransmitDelay(const mesh::Packet* packet) override;
|
uint32_t getDirectRetransmitDelay(const mesh::Packet* packet) override;
|
||||||
int getInterferenceThreshold() const override;
|
int getInterferenceThreshold() const override;
|
||||||
|
bool getCADEnabled() const override;
|
||||||
int getAGCResetInterval() const override;
|
int getAGCResetInterval() const override;
|
||||||
void onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, const mesh::Identity& sender, uint8_t* data, size_t len) override;
|
void onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, const mesh::Identity& sender, uint8_t* data, size_t len) override;
|
||||||
int searchPeersByHash(const uint8_t* hash) override;
|
int searchPeersByHash(const uint8_t* hash) override;
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// v1.2.3 (1 Jan 2025)
|
// v1.2.3 (1 Jan 2025)
|
||||||
sprintf(_version_info, "%s (%s)", version, build_date);
|
snprintf(_version_info, sizeof(_version_info), "%s (%s)", version, build_date);
|
||||||
|
free(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::renderCurrScreen() {
|
void UITask::renderCurrScreen() {
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ lib_deps =
|
|||||||
|
|
||||||
[env:native]
|
[env:native]
|
||||||
platform = native
|
platform = native
|
||||||
|
test_framework = googletest
|
||||||
build_flags = -std=c++17
|
build_flags = -std=c++17
|
||||||
-I src
|
-I src
|
||||||
-I test/mocks
|
-I test/mocks
|
||||||
@@ -164,5 +165,6 @@ test_build_src = yes
|
|||||||
build_src_filter =
|
build_src_filter =
|
||||||
-<*>
|
-<*>
|
||||||
+<../src/Utils.cpp>
|
+<../src/Utils.cpp>
|
||||||
|
+<../src/Packet.cpp>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
google/googletest @ 1.17.0
|
google/googletest @ 1.17.0
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ uint32_t Dispatcher::getCADFailMaxDuration() const {
|
|||||||
void Dispatcher::loop() {
|
void Dispatcher::loop() {
|
||||||
if (millisHasNowPassed(next_floor_calib_time)) {
|
if (millisHasNowPassed(next_floor_calib_time)) {
|
||||||
_radio->triggerNoiseFloorCalibrate(getInterferenceThreshold());
|
_radio->triggerNoiseFloorCalibrate(getInterferenceThreshold());
|
||||||
|
_radio->setCADEnabled(getCADEnabled());
|
||||||
next_floor_calib_time = futureMillis(NOISE_FLOOR_CALIB_INTERVAL);
|
next_floor_calib_time = futureMillis(NOISE_FLOOR_CALIB_INTERVAL);
|
||||||
}
|
}
|
||||||
_radio->loop();
|
_radio->loop();
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ public:
|
|||||||
|
|
||||||
virtual void triggerNoiseFloorCalibrate(int threshold) { }
|
virtual void triggerNoiseFloorCalibrate(int threshold) { }
|
||||||
|
|
||||||
|
virtual void setCADEnabled(bool enable) { }
|
||||||
|
|
||||||
virtual void resetAGC() { }
|
virtual void resetAGC() { }
|
||||||
|
|
||||||
virtual bool isInRecvMode() const = 0;
|
virtual bool isInRecvMode() const = 0;
|
||||||
@@ -166,6 +168,7 @@ protected:
|
|||||||
virtual uint32_t getCADFailRetryDelay() const;
|
virtual uint32_t getCADFailRetryDelay() const;
|
||||||
virtual uint32_t getCADFailMaxDuration() const;
|
virtual uint32_t getCADFailMaxDuration() const;
|
||||||
virtual int getInterferenceThreshold() const { return 0; } // disabled by default
|
virtual int getInterferenceThreshold() const { return 0; } // disabled by default
|
||||||
|
virtual bool getCADEnabled() const { return false; } // hardware CAD disabled by default
|
||||||
virtual int getAGCResetInterval() const { return 0; } // disabled by default
|
virtual int getAGCResetInterval() const { return 0; } // disabled by default
|
||||||
virtual unsigned long getDutyCycleWindowMs() const { return 3600000; }
|
virtual unsigned long getDutyCycleWindowMs() const { return 3600000; }
|
||||||
|
|
||||||
|
|||||||
+34
-17
@@ -50,10 +50,13 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
uint8_t path_sz = flags & 0x03; // NEW v1.11+: lower 2 bits is path hash size
|
uint8_t path_sz = flags & 0x03; // NEW v1.11+: lower 2 bits is path hash size
|
||||||
|
|
||||||
uint8_t len = pkt->payload_len - i;
|
uint8_t len = pkt->payload_len - i;
|
||||||
uint8_t offset = pkt->path_len << path_sz;
|
// path_len*entry_size can exceed 255 (path_len up to 63, entry_size up to 8);
|
||||||
|
// a uint8_t offset would wrap and steer the isHashMatch() read to the wrong place.
|
||||||
|
uint16_t offset = (uint16_t)pkt->path_len << path_sz;
|
||||||
if (offset >= len) { // TRACE has reached end of given path
|
if (offset >= len) { // TRACE has reached end of given path
|
||||||
onTraceRecv(pkt, trace_tag, auth_code, flags, pkt->path, &pkt->payload[i], len);
|
onTraceRecv(pkt, trace_tag, auth_code, flags, pkt->path, &pkt->payload[i], len);
|
||||||
} else if (self_id.isHashMatch(&pkt->payload[i + offset], 1 << path_sz) && allowPacketForward(pkt) && !_tables->hasSeen(pkt)) {
|
} else if (self_id.isHashMatch(&pkt->payload[i + offset], 1 << path_sz) && allowPacketForward(pkt) && !_tables->wasSeen(pkt)) {
|
||||||
|
_tables->markSeen(pkt);
|
||||||
// append SNR (Not hash!)
|
// append SNR (Not hash!)
|
||||||
pkt->path[pkt->path_len++] = (int8_t) (pkt->getSNR()*4);
|
pkt->path[pkt->path_len++] = (int8_t) (pkt->getSNR()*4);
|
||||||
|
|
||||||
@@ -87,14 +90,16 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
if (pkt->getPayloadType() == PAYLOAD_TYPE_MULTIPART) {
|
if (pkt->getPayloadType() == PAYLOAD_TYPE_MULTIPART) {
|
||||||
return forwardMultipartDirect(pkt);
|
return forwardMultipartDirect(pkt);
|
||||||
} else if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
|
} else if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
|
||||||
if (!_tables->hasSeen(pkt)) { // don't retransmit!
|
if (!_tables->wasSeen(pkt)) { // don't retransmit!
|
||||||
|
_tables->markSeen(pkt);
|
||||||
removeSelfFromPath(pkt);
|
removeSelfFromPath(pkt);
|
||||||
routeDirectRecvAcks(pkt, 0);
|
routeDirectRecvAcks(pkt, 0);
|
||||||
}
|
}
|
||||||
return ACTION_RELEASE;
|
return ACTION_RELEASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_tables->hasSeen(pkt)) {
|
if (!_tables->wasSeen(pkt)) {
|
||||||
|
_tables->markSeen(pkt);
|
||||||
removeSelfFromPath(pkt);
|
removeSelfFromPath(pkt);
|
||||||
|
|
||||||
uint32_t d = getDirectRetransmitDelay(pkt);
|
uint32_t d = getDirectRetransmitDelay(pkt);
|
||||||
@@ -115,7 +120,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
memcpy(&ack_crc, &pkt->payload[i], 4); i += 4;
|
memcpy(&ack_crc, &pkt->payload[i], 4); i += 4;
|
||||||
if (i > pkt->payload_len) {
|
if (i > pkt->payload_len) {
|
||||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete ACK packet", getLogDateTime());
|
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete ACK packet", getLogDateTime());
|
||||||
} else if (!_tables->hasSeen(pkt)) {
|
} else if (!_tables->wasSeen(pkt)) {
|
||||||
|
_tables->markSeen(pkt);
|
||||||
onAckRecv(pkt, ack_crc);
|
onAckRecv(pkt, ack_crc);
|
||||||
action = routeRecvPacket(pkt);
|
action = routeRecvPacket(pkt);
|
||||||
}
|
}
|
||||||
@@ -132,7 +138,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
||||||
if (i + CIPHER_MAC_SIZE >= pkt->payload_len) {
|
if (i + CIPHER_MAC_SIZE >= pkt->payload_len) {
|
||||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
||||||
} else if (!_tables->hasSeen(pkt)) {
|
} else if (!_tables->wasSeen(pkt)) {
|
||||||
|
_tables->markSeen(pkt);
|
||||||
// NOTE: this is a 'first packet wins' impl. When receiving from multiple paths, the first to arrive wins.
|
// NOTE: this is a 'first packet wins' impl. When receiving from multiple paths, the first to arrive wins.
|
||||||
// For flood mode, the path may not be the 'best' in terms of hops.
|
// For flood mode, the path may not be the 'best' in terms of hops.
|
||||||
// FUTURE: could send back multiple paths, using createPathReturn(), and let sender choose which to use(?)
|
// FUTURE: could send back multiple paths, using createPathReturn(), and let sender choose which to use(?)
|
||||||
@@ -153,6 +160,10 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
||||||
int k = 0;
|
int k = 0;
|
||||||
uint8_t path_len = data[k++];
|
uint8_t path_len = data[k++];
|
||||||
|
if (!Packet::isValidPathLen(path_len)) {
|
||||||
|
MESH_DEBUG_PRINTLN("%s PAYLOAD_TYPE_PATH, bad path_len: %u", getLogDateTime(), (uint32_t)path_len);
|
||||||
|
break; // reject bad encoding
|
||||||
|
}
|
||||||
uint8_t hash_size = (path_len >> 6) + 1;
|
uint8_t hash_size = (path_len >> 6) + 1;
|
||||||
uint8_t hash_count = path_len & 63;
|
uint8_t hash_count = path_len & 63;
|
||||||
uint8_t* path = &data[k]; k += hash_size*hash_count;
|
uint8_t* path = &data[k]; k += hash_size*hash_count;
|
||||||
@@ -191,7 +202,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
||||||
if (i + 2 >= pkt->payload_len) {
|
if (i + 2 >= pkt->payload_len) {
|
||||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
||||||
} else if (!_tables->hasSeen(pkt)) {
|
} else if (!_tables->wasSeen(pkt)) {
|
||||||
|
_tables->markSeen(pkt);
|
||||||
if (self_id.isHashMatch(&dest_hash)) {
|
if (self_id.isHashMatch(&dest_hash)) {
|
||||||
Identity sender(sender_pub_key);
|
Identity sender(sender_pub_key);
|
||||||
|
|
||||||
@@ -218,7 +230,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
||||||
if (i + 2 >= pkt->payload_len) {
|
if (i + 2 >= pkt->payload_len) {
|
||||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
||||||
} else if (!_tables->hasSeen(pkt)) {
|
} else if (!_tables->wasSeen(pkt)) {
|
||||||
|
_tables->markSeen(pkt);
|
||||||
// scan channels DB, for all matching hashes of 'channel_hash' (max 4 matches supported ATM)
|
// scan channels DB, for all matching hashes of 'channel_hash' (max 4 matches supported ATM)
|
||||||
GroupChannel channels[4];
|
GroupChannel channels[4];
|
||||||
int num = searchChannelsByHash(&channel_hash, channels, 4);
|
int num = searchChannelsByHash(&channel_hash, channels, 4);
|
||||||
@@ -249,7 +262,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete advertisement packet", getLogDateTime());
|
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete advertisement packet", getLogDateTime());
|
||||||
} else if (self_id.matches(id.pub_key)) {
|
} else if (self_id.matches(id.pub_key)) {
|
||||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): receiving SELF advert packet", getLogDateTime());
|
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): receiving SELF advert packet", getLogDateTime());
|
||||||
} else if (!_tables->hasSeen(pkt)) {
|
} else if (!_tables->wasSeen(pkt)) {
|
||||||
|
_tables->markSeen(pkt);
|
||||||
uint8_t* app_data = &pkt->payload[i];
|
uint8_t* app_data = &pkt->payload[i];
|
||||||
int app_data_len = pkt->payload_len - i;
|
int app_data_len = pkt->payload_len - i;
|
||||||
if (app_data_len > MAX_ADVERT_DATA_SIZE) { app_data_len = MAX_ADVERT_DATA_SIZE; }
|
if (app_data_len > MAX_ADVERT_DATA_SIZE) { app_data_len = MAX_ADVERT_DATA_SIZE; }
|
||||||
@@ -276,7 +290,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PAYLOAD_TYPE_RAW_CUSTOM: {
|
case PAYLOAD_TYPE_RAW_CUSTOM: {
|
||||||
if (pkt->isRouteDirect() && !_tables->hasSeen(pkt)) {
|
if (pkt->isRouteDirect() && !_tables->wasSeen(pkt)) {
|
||||||
|
_tables->markSeen(pkt);
|
||||||
onRawDataRecv(pkt);
|
onRawDataRecv(pkt);
|
||||||
//action = routeRecvPacket(pkt); don't flood route these (yet)
|
//action = routeRecvPacket(pkt); don't flood route these (yet)
|
||||||
}
|
}
|
||||||
@@ -294,7 +309,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
|||||||
tmp.payload_len = pkt->payload_len - 1;
|
tmp.payload_len = pkt->payload_len - 1;
|
||||||
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
|
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
|
||||||
|
|
||||||
if (!_tables->hasSeen(&tmp)) {
|
if (!_tables->wasSeen(&tmp)) {
|
||||||
|
_tables->markSeen(&tmp);
|
||||||
uint32_t ack_crc;
|
uint32_t ack_crc;
|
||||||
memcpy(&ack_crc, tmp.payload, 4);
|
memcpy(&ack_crc, tmp.payload, 4);
|
||||||
|
|
||||||
@@ -351,7 +367,8 @@ DispatcherAction Mesh::forwardMultipartDirect(Packet* pkt) {
|
|||||||
tmp.payload_len = pkt->payload_len - 1;
|
tmp.payload_len = pkt->payload_len - 1;
|
||||||
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
|
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
|
||||||
|
|
||||||
if (!_tables->hasSeen(&tmp)) { // don't retransmit!
|
if (!_tables->wasSeen(&tmp)) { // don't retransmit!
|
||||||
|
_tables->markSeen(&tmp);
|
||||||
removeSelfFromPath(&tmp);
|
removeSelfFromPath(&tmp);
|
||||||
routeDirectRecvAcks(&tmp, ((uint32_t)remaining + 1) * 300); // expect multipart ACKs 300ms apart (x2)
|
routeDirectRecvAcks(&tmp, ((uint32_t)remaining + 1) * 300); // expect multipart ACKs 300ms apart (x2)
|
||||||
}
|
}
|
||||||
@@ -631,7 +648,7 @@ void Mesh::sendFlood(Packet* packet, uint32_t delay_millis, uint8_t path_hash_si
|
|||||||
packet->header |= ROUTE_TYPE_FLOOD;
|
packet->header |= ROUTE_TYPE_FLOOD;
|
||||||
packet->setPathHashSizeAndCount(path_hash_size, 0);
|
packet->setPathHashSizeAndCount(path_hash_size, 0);
|
||||||
|
|
||||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||||
|
|
||||||
uint8_t pri;
|
uint8_t pri;
|
||||||
if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
||||||
@@ -660,7 +677,7 @@ void Mesh::sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_m
|
|||||||
packet->transport_codes[1] = transport_codes[1];
|
packet->transport_codes[1] = transport_codes[1];
|
||||||
packet->setPathHashSizeAndCount(path_hash_size, 0);
|
packet->setPathHashSizeAndCount(path_hash_size, 0);
|
||||||
|
|
||||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||||
|
|
||||||
uint8_t pri;
|
uint8_t pri;
|
||||||
if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
||||||
@@ -693,7 +710,7 @@ void Mesh::sendDirect(Packet* packet, const uint8_t* path, uint8_t path_len, uin
|
|||||||
pri = 0;
|
pri = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||||
sendPacket(packet, pri, delay_millis);
|
sendPacket(packet, pri, delay_millis);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,7 +720,7 @@ void Mesh::sendZeroHop(Packet* packet, uint32_t delay_millis) {
|
|||||||
|
|
||||||
packet->path_len = 0; // path_len of zero means Zero Hop
|
packet->path_len = 0; // path_len of zero means Zero Hop
|
||||||
|
|
||||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||||
|
|
||||||
sendPacket(packet, 0, delay_millis);
|
sendPacket(packet, 0, delay_millis);
|
||||||
}
|
}
|
||||||
@@ -716,7 +733,7 @@ void Mesh::sendZeroHop(Packet* packet, uint16_t* transport_codes, uint32_t delay
|
|||||||
|
|
||||||
packet->path_len = 0; // path_len of zero means Zero Hop
|
packet->path_len = 0; // path_len of zero means Zero Hop
|
||||||
|
|
||||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||||
|
|
||||||
sendPacket(packet, 0, delay_millis);
|
sendPacket(packet, 0, delay_millis);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -15,8 +15,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
class MeshTables {
|
class MeshTables {
|
||||||
public:
|
public:
|
||||||
virtual bool hasSeen(const Packet* packet) = 0;
|
virtual bool wasSeen(const Packet* packet) = 0;
|
||||||
virtual void clear(const Packet* packet) = 0; // remove this packet hash from table
|
virtual void markSeen(const Packet* packet) = 0;
|
||||||
|
virtual void clear(const Packet* packet) = 0; // remove this packet hash from table
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,7 +101,7 @@ protected:
|
|||||||
* \param auth_code a code to authenticate the packet
|
* \param auth_code a code to authenticate the packet
|
||||||
* \param flags zero for now
|
* \param flags zero for now
|
||||||
* \param path_snrs single byte SNR*4 for each hop in the path
|
* \param path_snrs single byte SNR*4 for each hop in the path
|
||||||
* \param path_hashes hashes if each repeater in the path
|
* \param path_hashes hashes of each repeater in the path
|
||||||
* \param path_len length of the path_snrs[] and path_hashes[] arrays
|
* \param path_len length of the path_snrs[] and path_hashes[] arrays
|
||||||
*/
|
*/
|
||||||
virtual void onTraceRecv(Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, const uint8_t* path_hashes, uint8_t path_len) { }
|
virtual void onTraceRecv(Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, const uint8_t* path_hashes, uint8_t path_len) { }
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ public:
|
|||||||
virtual uint8_t getStartupReason() const = 0;
|
virtual uint8_t getStartupReason() const = 0;
|
||||||
virtual bool getBootloaderVersion(char* version, size_t max_len) { return false; }
|
virtual bool getBootloaderVersion(char* version, size_t max_len) { return false; }
|
||||||
virtual bool startOTAUpdate(const char* id, char reply[]) { return false; } // not supported
|
virtual bool startOTAUpdate(const char* id, char reply[]) { return false; } // not supported
|
||||||
|
virtual bool setLoRaFemLnaEnabled(bool enable) { return false; }
|
||||||
|
virtual bool canControlLoRaFemLna() const { return false; }
|
||||||
|
virtual bool isLoRaFemLnaEnabled() const { return false; }
|
||||||
|
|
||||||
// Power management interface (boards with power management override these)
|
// Power management interface (boards with power management override these)
|
||||||
virtual bool isExternalPowered() { return false; }
|
virtual bool isExternalPowered() { return false; }
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ namespace mesh {
|
|||||||
#define PAYLOAD_TYPE_GRP_DATA 0x06 // an (unverified) group datagram (prefixed with channel hash, MAC) (enc data: data_type(uint16), data_len, blob)
|
#define PAYLOAD_TYPE_GRP_DATA 0x06 // an (unverified) group datagram (prefixed with channel hash, MAC) (enc data: data_type(uint16), data_len, blob)
|
||||||
#define PAYLOAD_TYPE_ANON_REQ 0x07 // generic request (prefixed with dest_hash, ephemeral pub_key, MAC) (enc data: ...)
|
#define PAYLOAD_TYPE_ANON_REQ 0x07 // generic request (prefixed with dest_hash, ephemeral pub_key, MAC) (enc data: ...)
|
||||||
#define PAYLOAD_TYPE_PATH 0x08 // returned path (prefixed with dest/src hashes, MAC) (enc data: path, extra)
|
#define PAYLOAD_TYPE_PATH 0x08 // returned path (prefixed with dest/src hashes, MAC) (enc data: path, extra)
|
||||||
#define PAYLOAD_TYPE_TRACE 0x09 // trace a path, collecting SNI for each hop
|
#define PAYLOAD_TYPE_TRACE 0x09 // trace a path, collecting SNR for each hop
|
||||||
#define PAYLOAD_TYPE_MULTIPART 0x0A // packet is one of a set of packets
|
#define PAYLOAD_TYPE_MULTIPART 0x0A // packet is one of a set of packets
|
||||||
#define PAYLOAD_TYPE_CONTROL 0x0B // a control/discovery packet
|
#define PAYLOAD_TYPE_CONTROL 0x0B // a control/discovery packet
|
||||||
//...
|
//...
|
||||||
|
|||||||
@@ -68,29 +68,36 @@ void BaseChatMesh::bootstrapRTCfromContacts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ContactInfo* BaseChatMesh::allocateContactSlot(bool transient_only) {
|
ContactInfo* BaseChatMesh::allocateContactSlot(bool transient_only) {
|
||||||
if (num_contacts < MAX_CONTACTS) {
|
int oldest_idx = -1;
|
||||||
return &contacts[num_contacts++];
|
uint32_t oldest_lastmod = 0xFFFFFFFF;
|
||||||
} else if (transient_only || shouldOverwriteWhenFull()) {
|
if (transient_only) {
|
||||||
// Find oldest non-favourite contact by oldest lastmod timestamp
|
// only allocate from first N
|
||||||
int oldest_idx = -1;
|
for (int i = 0; i < MAX_ANON_CONTACTS; i++) {
|
||||||
uint32_t oldest_lastmod = 0xFFFFFFFF;
|
if (contacts[i].type == ADV_TYPE_NONE && contacts[i].lastmod < oldest_lastmod) {
|
||||||
for (int i = 0; i < num_contacts; i++) {
|
oldest_lastmod = contacts[i].lastmod;
|
||||||
if (transient_only) {
|
oldest_idx = i;
|
||||||
if (contacts[i].type == ADV_TYPE_NONE && contacts[i].lastmod < oldest_lastmod) {
|
}
|
||||||
oldest_lastmod = contacts[i].lastmod;
|
}
|
||||||
oldest_idx = i;
|
if (oldest_idx >= 0) {
|
||||||
}
|
// NOTE: do NOT call onContactOverwrite()
|
||||||
} else {
|
return &contacts[oldest_idx];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (num_contacts < MAX_ANON_CONTACTS+MAX_CONTACTS) {
|
||||||
|
return &contacts[num_contacts++];
|
||||||
|
} else if (shouldOverwriteWhenFull()) {
|
||||||
|
// Find oldest non-favourite contact by oldest lastmod timestamp
|
||||||
|
for (int i = MAX_ANON_CONTACTS; i < num_contacts; i++) {
|
||||||
bool is_favourite = (contacts[i].flags & 0x01) != 0;
|
bool is_favourite = (contacts[i].flags & 0x01) != 0;
|
||||||
if (!is_favourite && contacts[i].lastmod < oldest_lastmod && contacts[i].type != ADV_TYPE_NONE) {
|
if (!is_favourite && contacts[i].lastmod < oldest_lastmod) {
|
||||||
oldest_lastmod = contacts[i].lastmod;
|
oldest_lastmod = contacts[i].lastmod;
|
||||||
oldest_idx = i;
|
oldest_idx = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (oldest_idx >= 0) {
|
||||||
if (oldest_idx >= 0) {
|
onContactOverwrite(contacts[oldest_idx].id.pub_key);
|
||||||
onContactOverwrite(contacts[oldest_idx].id.pub_key);
|
return &contacts[oldest_idx];
|
||||||
return &contacts[oldest_idx];
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL; // no space, no overwrite or all contacts are all favourites
|
return NULL; // no space, no overwrite or all contacts are all favourites
|
||||||
@@ -139,6 +146,11 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id,
|
|||||||
packet->header = save;
|
packet->header = save;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (from && from->type == ADV_TYPE_NONE) { // already in contacts, but from a temporary ANON_REQ ?
|
||||||
|
memset(from, 0, sizeof(*from)); // clear the anon/temp slot
|
||||||
|
from = NULL; // do normal 'add' flow
|
||||||
|
}
|
||||||
|
|
||||||
bool is_new = false; // true = not in contacts[], false = exists in contacts[]
|
bool is_new = false; // true = not in contacts[], false = exists in contacts[]
|
||||||
if (from == NULL) {
|
if (from == NULL) {
|
||||||
if (!shouldAutoAddContactType(parser.getType())) {
|
if (!shouldAutoAddContactType(parser.getType())) {
|
||||||
@@ -930,11 +942,11 @@ bool BaseChatMesh::getContactByIdx(uint32_t idx, ContactInfo& contact) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ContactsIterator BaseChatMesh::startContactsIterator() {
|
ContactsIterator BaseChatMesh::startContactsIterator() {
|
||||||
return ContactsIterator();
|
return ContactsIterator(MAX_ANON_CONTACTS); // start at offset, skip the anon entries
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContactsIterator::hasNext(const BaseChatMesh* mesh, ContactInfo& dest) {
|
bool ContactsIterator::hasNext(const BaseChatMesh* mesh, ContactInfo& dest) {
|
||||||
if (next_idx >= mesh->getNumContacts()) return false;
|
if (next_idx >= mesh->getTotalContactSlots()) return false;
|
||||||
|
|
||||||
dest = mesh->contacts[next_idx++];
|
dest = mesh->contacts[next_idx++];
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -28,8 +28,9 @@ public:
|
|||||||
class BaseChatMesh;
|
class BaseChatMesh;
|
||||||
|
|
||||||
class ContactsIterator {
|
class ContactsIterator {
|
||||||
int next_idx = 0;
|
int next_idx;
|
||||||
public:
|
public:
|
||||||
|
ContactsIterator(int start) { next_idx = start; }
|
||||||
bool hasNext(const BaseChatMesh* mesh, ContactInfo& dest);
|
bool hasNext(const BaseChatMesh* mesh, ContactInfo& dest);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,7 +81,8 @@ protected:
|
|||||||
BaseChatMesh(mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::PacketManager& mgr, mesh::MeshTables& tables)
|
BaseChatMesh(mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::PacketManager& mgr, mesh::MeshTables& tables)
|
||||||
: mesh::Mesh(radio, ms, rng, rtc, mgr, tables)
|
: mesh::Mesh(radio, ms, rng, rtc, mgr, tables)
|
||||||
{
|
{
|
||||||
num_contacts = 0;
|
resetContacts();
|
||||||
|
|
||||||
#ifdef MAX_GROUP_CHANNELS
|
#ifdef MAX_GROUP_CHANNELS
|
||||||
memset(channels, 0, sizeof(channels));
|
memset(channels, 0, sizeof(channels));
|
||||||
num_channels = 0;
|
num_channels = 0;
|
||||||
@@ -91,7 +93,11 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void bootstrapRTCfromContacts();
|
void bootstrapRTCfromContacts();
|
||||||
void resetContacts() { num_contacts = 0; }
|
|
||||||
|
void resetContacts() {
|
||||||
|
memset(contacts, 0, sizeof(contacts[0])*MAX_ANON_CONTACTS); // set all to have type = ADV_TYPE_NONE(0)
|
||||||
|
num_contacts = MAX_ANON_CONTACTS; // seed the first contacts for anon requests
|
||||||
|
}
|
||||||
void populateContactFromAdvert(ContactInfo& ci, const mesh::Identity& id, const AdvertDataParser& parser, uint32_t timestamp);
|
void populateContactFromAdvert(ContactInfo& ci, const mesh::Identity& id, const AdvertDataParser& parser, uint32_t timestamp);
|
||||||
ContactInfo* allocateContactSlot(bool transient_only=false); // helper to find slot for new contact
|
ContactInfo* allocateContactSlot(bool transient_only=false); // helper to find slot for new contact
|
||||||
|
|
||||||
@@ -166,7 +172,8 @@ public:
|
|||||||
ContactInfo* lookupContactByPubKey(const uint8_t* pub_key, int prefix_len);
|
ContactInfo* lookupContactByPubKey(const uint8_t* pub_key, int prefix_len);
|
||||||
bool removeContact(ContactInfo& contact);
|
bool removeContact(ContactInfo& contact);
|
||||||
bool addContact(const ContactInfo& contact);
|
bool addContact(const ContactInfo& contact);
|
||||||
int getNumContacts() const { return num_contacts; }
|
int getTotalContactSlots() const { return num_contacts; }
|
||||||
|
int getNumContacts() const { return num_contacts - MAX_ANON_CONTACTS; } // don't include the reserved slots at start
|
||||||
bool getContactByIdx(uint32_t idx, ContactInfo& contact);
|
bool getContactByIdx(uint32_t idx, ContactInfo& contact);
|
||||||
ContactsIterator startContactsIterator();
|
ContactsIterator startContactsIterator();
|
||||||
ChannelDetails* addChannel(const char* name, const char* psk_base64);
|
ChannelDetails* addChannel(const char* name, const char* psk_base64);
|
||||||
|
|||||||
+58
-22
@@ -88,10 +88,12 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
|||||||
file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
||||||
file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
||||||
file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
|
file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
|
||||||
file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
|
file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
|
||||||
file.read((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
|
file.read((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
|
||||||
file.read((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
|
file.read((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
|
||||||
// next: 293
|
file.read((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 293
|
||||||
|
file.read((uint8_t *)&_prefs->cad_enabled, sizeof(_prefs->cad_enabled)); // 294
|
||||||
|
// next: 295
|
||||||
|
|
||||||
// sanitise bad pref values
|
// sanitise bad pref values
|
||||||
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
|
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
|
||||||
@@ -121,6 +123,8 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
|||||||
|
|
||||||
// sanitise settings
|
// sanitise settings
|
||||||
_prefs->rx_boosted_gain = constrain(_prefs->rx_boosted_gain, 0, 1); // boolean
|
_prefs->rx_boosted_gain = constrain(_prefs->rx_boosted_gain, 0, 1); // boolean
|
||||||
|
_prefs->radio_fem_rxgain = constrain(_prefs->radio_fem_rxgain, 0, 1); // boolean
|
||||||
|
_prefs->cad_enabled = constrain(_prefs->cad_enabled, 0, 1); // boolean
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
@@ -181,10 +185,12 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
|||||||
file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
||||||
file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
||||||
file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
|
file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
|
||||||
file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
|
file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
|
||||||
file.write((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
|
file.write((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
|
||||||
file.write((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
|
file.write((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
|
||||||
// next: 293
|
file.write((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 293
|
||||||
|
file.write((uint8_t *)&_prefs->cad_enabled, sizeof(_prefs->cad_enabled)); // 294
|
||||||
|
// next: 295
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
@@ -500,6 +506,10 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
|||||||
_prefs->interference_threshold = atoi(&config[11]);
|
_prefs->interference_threshold = atoi(&config[11]);
|
||||||
savePrefs();
|
savePrefs();
|
||||||
strcpy(reply, "OK");
|
strcpy(reply, "OK");
|
||||||
|
} else if (memcmp(config, "cad ", 4) == 0) {
|
||||||
|
_prefs->cad_enabled = memcmp(&config[4], "on", 2) == 0;
|
||||||
|
savePrefs();
|
||||||
|
strcpy(reply, "OK");
|
||||||
} else if (memcmp(config, "agc.reset.interval ", 19) == 0) {
|
} else if (memcmp(config, "agc.reset.interval ", 19) == 0) {
|
||||||
_prefs->agc_reset_interval = atoi(&config[19]) / 4;
|
_prefs->agc_reset_interval = atoi(&config[19]) / 4;
|
||||||
savePrefs();
|
savePrefs();
|
||||||
@@ -561,13 +571,37 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
|||||||
_prefs->disable_fwd = memcmp(&config[7], "off", 3) == 0;
|
_prefs->disable_fwd = memcmp(&config[7], "off", 3) == 0;
|
||||||
savePrefs();
|
savePrefs();
|
||||||
strcpy(reply, _prefs->disable_fwd ? "OK - repeat is now OFF" : "OK - repeat is now ON");
|
strcpy(reply, _prefs->disable_fwd ? "OK - repeat is now OFF" : "OK - repeat is now ON");
|
||||||
#if defined(USE_SX1262) || defined(USE_SX1268) || defined(USE_LR1110)
|
|
||||||
} else if (memcmp(config, "radio.rxgain ", 13) == 0) {
|
} else if (memcmp(config, "radio.rxgain ", 13) == 0) {
|
||||||
_prefs->rx_boosted_gain = memcmp(&config[13], "on", 2) == 0;
|
bool enabled = memcmp(&config[13], "on", 2) == 0;
|
||||||
strcpy(reply, "OK");
|
_prefs->rx_boosted_gain = enabled;
|
||||||
savePrefs();
|
savePrefs();
|
||||||
_callbacks->setRxBoostedGain(_prefs->rx_boosted_gain);
|
if (_callbacks->setRxBoostedGain(enabled)) {
|
||||||
#endif
|
strcpy(reply, "OK");
|
||||||
|
} else {
|
||||||
|
strcpy(reply, "Error: unsupported");
|
||||||
|
}
|
||||||
|
} else if (memcmp(config, "radio.fem.rxgain ", 17) == 0) {
|
||||||
|
if (!_board->canControlLoRaFemLna()) {
|
||||||
|
strcpy(reply, "Error: unsupported");
|
||||||
|
} else if (memcmp(&config[17], "on", 2) == 0) {
|
||||||
|
if (_board->setLoRaFemLnaEnabled(true)) {
|
||||||
|
_prefs->radio_fem_rxgain = 1;
|
||||||
|
savePrefs();
|
||||||
|
strcpy(reply, "OK - LoRa FEM RX gain on");
|
||||||
|
} else {
|
||||||
|
strcpy(reply, "Error: failed to apply LoRa FEM RX gain");
|
||||||
|
}
|
||||||
|
} else if (memcmp(&config[17], "off", 3) == 0) {
|
||||||
|
if (_board->setLoRaFemLnaEnabled(false)) {
|
||||||
|
_prefs->radio_fem_rxgain = 0;
|
||||||
|
savePrefs();
|
||||||
|
strcpy(reply, "OK - LoRa FEM RX gain off");
|
||||||
|
} else {
|
||||||
|
strcpy(reply, "Error: failed to apply LoRa FEM RX gain");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strcpy(reply, "Error: state must be on or off");
|
||||||
|
}
|
||||||
} else if (memcmp(config, "radio ", 6) == 0) {
|
} else if (memcmp(config, "radio ", 6) == 0) {
|
||||||
strcpy(tmp, &config[6]);
|
strcpy(tmp, &config[6]);
|
||||||
const char *parts[4];
|
const char *parts[4];
|
||||||
@@ -757,7 +791,7 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_prefs->adc_multiplier = 0.0f;
|
_prefs->adc_multiplier = 0.0f;
|
||||||
strcpy(reply, "Error: unsupported by this board");
|
strcpy(reply, "Error: unsupported");
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
strcpy(reply, "unknown config: ");
|
strcpy(reply, "unknown config: ");
|
||||||
@@ -776,6 +810,8 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
|||||||
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor));
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor));
|
||||||
} else if (memcmp(config, "int.thresh", 10) == 0) {
|
} else if (memcmp(config, "int.thresh", 10) == 0) {
|
||||||
sprintf(reply, "> %d", (uint32_t) _prefs->interference_threshold);
|
sprintf(reply, "> %d", (uint32_t) _prefs->interference_threshold);
|
||||||
|
} else if (memcmp(config, "cad", 3) == 0) {
|
||||||
|
sprintf(reply, "> %s", _prefs->cad_enabled ? "on" : "off");
|
||||||
} else if (memcmp(config, "agc.reset.interval", 18) == 0) {
|
} else if (memcmp(config, "agc.reset.interval", 18) == 0) {
|
||||||
sprintf(reply, "> %d", ((uint32_t) _prefs->agc_reset_interval) * 4);
|
sprintf(reply, "> %d", ((uint32_t) _prefs->agc_reset_interval) * 4);
|
||||||
} else if (memcmp(config, "multi.acks", 10) == 0) {
|
} else if (memcmp(config, "multi.acks", 10) == 0) {
|
||||||
@@ -801,10 +837,14 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
|||||||
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lat));
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lat));
|
||||||
} else if (memcmp(config, "lon", 3) == 0) {
|
} else if (memcmp(config, "lon", 3) == 0) {
|
||||||
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lon));
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lon));
|
||||||
#if defined(USE_SX1262) || defined(USE_SX1268) || defined(USE_LR1110)
|
|
||||||
} else if (memcmp(config, "radio.rxgain", 12) == 0) {
|
} else if (memcmp(config, "radio.rxgain", 12) == 0) {
|
||||||
sprintf(reply, "> %s", _prefs->rx_boosted_gain ? "on" : "off");
|
sprintf(reply, "> %s", _prefs->rx_boosted_gain ? "on" : "off");
|
||||||
#endif
|
} else if (memcmp(config, "radio.fem.rxgain", 16) == 0) {
|
||||||
|
if (!_board->canControlLoRaFemLna()) {
|
||||||
|
strcpy(reply, "Error: unsupported");
|
||||||
|
} else {
|
||||||
|
sprintf(reply, "> %s", _board->isLoRaFemLnaEnabled() ? "on" : "off");
|
||||||
|
}
|
||||||
} else if (memcmp(config, "radio", 5) == 0) {
|
} else if (memcmp(config, "radio", 5) == 0) {
|
||||||
char freq[16], bw[16];
|
char freq[16], bw[16];
|
||||||
strcpy(freq, StrHelper::ftoa(_prefs->freq));
|
strcpy(freq, StrHelper::ftoa(_prefs->freq));
|
||||||
@@ -890,12 +930,12 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
|||||||
strcpy(reply, "> unknown");
|
strcpy(reply, "> unknown");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
strcpy(reply, "ERROR: unsupported");
|
strcpy(reply, "Error: unsupported");
|
||||||
#endif
|
#endif
|
||||||
} else if (memcmp(config, "adc.multiplier", 14) == 0) {
|
} else if (memcmp(config, "adc.multiplier", 14) == 0) {
|
||||||
float adc_mult = _board->getAdcMultiplier();
|
float adc_mult = _board->getAdcMultiplier();
|
||||||
if (adc_mult == 0.0f) {
|
if (adc_mult == 0.0f) {
|
||||||
strcpy(reply, "Error: unsupported by this board");
|
strcpy(reply, "Error: unsupported");
|
||||||
} else {
|
} else {
|
||||||
sprintf(reply, "> %.3f", adc_mult);
|
sprintf(reply, "> %.3f", adc_mult);
|
||||||
}
|
}
|
||||||
@@ -913,13 +953,9 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
|||||||
strcpy(reply, "ERROR: Power management not supported");
|
strcpy(reply, "ERROR: Power management not supported");
|
||||||
#endif
|
#endif
|
||||||
} else if (memcmp(config, "pwrmgt.bootreason", 17) == 0) {
|
} else if (memcmp(config, "pwrmgt.bootreason", 17) == 0) {
|
||||||
#ifdef NRF52_POWER_MANAGEMENT
|
|
||||||
sprintf(reply, "> Reset: %s; Shutdown: %s",
|
sprintf(reply, "> Reset: %s; Shutdown: %s",
|
||||||
_board->getResetReasonString(_board->getResetReason()),
|
_board->getResetReasonString(_board->getResetReason()),
|
||||||
_board->getShutdownReasonString(_board->getShutdownReason()));
|
_board->getShutdownReasonString(_board->getShutdownReason()));
|
||||||
#else
|
|
||||||
strcpy(reply, "ERROR: Power management not supported");
|
|
||||||
#endif
|
|
||||||
} else if (memcmp(config, "pwrmgt.bootmv", 13) == 0) {
|
} else if (memcmp(config, "pwrmgt.bootmv", 13) == 0) {
|
||||||
#ifdef NRF52_POWER_MANAGEMENT
|
#ifdef NRF52_POWER_MANAGEMENT
|
||||||
sprintf(reply, "> %u mV", _board->getBootVoltage());
|
sprintf(reply, "> %u mV", _board->getBootVoltage());
|
||||||
|
|||||||
@@ -61,8 +61,10 @@ struct NodePrefs { // persisted to file
|
|||||||
float adc_multiplier;
|
float adc_multiplier;
|
||||||
char owner_info[120];
|
char owner_info[120];
|
||||||
uint8_t rx_boosted_gain; // power settings
|
uint8_t rx_boosted_gain; // power settings
|
||||||
|
uint8_t radio_fem_rxgain; // LoRa FEM RX gain setting
|
||||||
uint8_t path_hash_mode; // which path mode to use when sending
|
uint8_t path_hash_mode; // which path mode to use when sending
|
||||||
uint8_t loop_detect;
|
uint8_t loop_detect;
|
||||||
|
uint8_t cad_enabled; // hardware Channel Activity Detection before TX (boolean)
|
||||||
};
|
};
|
||||||
|
|
||||||
class CommonCLICallbacks {
|
class CommonCLICallbacks {
|
||||||
@@ -109,8 +111,8 @@ public:
|
|||||||
// no op by default
|
// no op by default
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void setRxBoostedGain(bool enable) {
|
virtual bool setRxBoostedGain(bool enable) {
|
||||||
// no op by default
|
return false; // CommonCLI reports unsupported if not overridden by wrapper
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -155,6 +155,42 @@ public:
|
|||||||
void setInhibitSleep(bool inhibit) {
|
void setInhibitSleep(bool inhibit) {
|
||||||
inhibit_sleep = inhibit;
|
inhibit_sleep = inhibit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t getResetReason() const override {
|
||||||
|
return esp_reset_reason();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.espressif.com/projects/esp-idf/en/v4.4.7/esp32/api-reference/system/system.html
|
||||||
|
const char* getResetReasonString(uint32_t reason) {
|
||||||
|
switch (reason) {
|
||||||
|
case ESP_RST_UNKNOWN:
|
||||||
|
return "Unknown or first boot";
|
||||||
|
case ESP_RST_POWERON:
|
||||||
|
return "Power-on reset";
|
||||||
|
case ESP_RST_EXT:
|
||||||
|
return "External reset";
|
||||||
|
case ESP_RST_SW:
|
||||||
|
return "Software reset";
|
||||||
|
case ESP_RST_PANIC:
|
||||||
|
return "Panic / exception reset";
|
||||||
|
case ESP_RST_INT_WDT:
|
||||||
|
return "Interrupt watchdog reset";
|
||||||
|
case ESP_RST_TASK_WDT:
|
||||||
|
return "Task watchdog reset";
|
||||||
|
case ESP_RST_WDT:
|
||||||
|
return "Other watchdog reset";
|
||||||
|
case ESP_RST_DEEPSLEEP:
|
||||||
|
return "Wake from deep sleep";
|
||||||
|
case ESP_RST_BROWNOUT:
|
||||||
|
return "Brownout (low voltage)";
|
||||||
|
case ESP_RST_SDIO:
|
||||||
|
return "SDIO reset";
|
||||||
|
default:
|
||||||
|
static char buf[40];
|
||||||
|
snprintf(buf, sizeof(buf), "Unknown reset reason (%d)", reason);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ESP32RTCClock : public mesh::RTCClock {
|
class ESP32RTCClock : public mesh::RTCClock {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool hasSeen(const mesh::Packet* packet) override {
|
bool wasSeen(const mesh::Packet* packet) override {
|
||||||
uint8_t hash[MAX_HASH_SIZE];
|
uint8_t hash[MAX_HASH_SIZE];
|
||||||
packet->calculatePacketHash(hash);
|
packet->calculatePacketHash(hash);
|
||||||
|
|
||||||
@@ -39,19 +39,23 @@ public:
|
|||||||
for (int i = 0; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
|
for (int i = 0; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
|
||||||
if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) {
|
if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) {
|
||||||
if (packet->isRouteDirect()) {
|
if (packet->isRouteDirect()) {
|
||||||
_direct_dups++; // keep some stats
|
_direct_dups++;
|
||||||
} else {
|
} else {
|
||||||
_flood_dups++;
|
_flood_dups++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&_hashes[_next_idx*MAX_HASH_SIZE], hash, MAX_HASH_SIZE);
|
|
||||||
_next_idx = (_next_idx + 1) % MAX_PACKET_HASHES; // cyclic table
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void markSeen(const mesh::Packet* packet) override {
|
||||||
|
uint8_t hash[MAX_HASH_SIZE];
|
||||||
|
packet->calculatePacketHash(hash);
|
||||||
|
memcpy(&_hashes[_next_idx * MAX_HASH_SIZE], hash, MAX_HASH_SIZE);
|
||||||
|
_next_idx = (_next_idx + 1) % MAX_PACKET_HASHES;
|
||||||
|
}
|
||||||
|
|
||||||
void clear(const mesh::Packet* packet) override {
|
void clear(const mesh::Packet* packet) override {
|
||||||
uint8_t hash[MAX_HASH_SIZE];
|
uint8_t hash[MAX_HASH_SIZE];
|
||||||
packet->calculatePacketHash(hash);
|
packet->calculatePacketHash(hash);
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ void BridgeBase::handleReceivedPacket(mesh::Packet *packet) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_seen_packets.hasSeen(packet)) {
|
if (!_seen_packets.wasSeen(packet)) {
|
||||||
|
_seen_packets.markSeen(packet);
|
||||||
// bridge_delay provides a buffer to prevent immediate processing conflicts in the mesh network.
|
// bridge_delay provides a buffer to prevent immediate processing conflicts in the mesh network.
|
||||||
_mgr->queueInbound(packet, millis() + _prefs->bridge_delay);
|
_mgr->queueInbound(packet, millis() + _prefs->bridge_delay);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ protected:
|
|||||||
* @brief Common packet handling for received packets
|
* @brief Common packet handling for received packets
|
||||||
*
|
*
|
||||||
* Implements the standard pattern used by all bridges:
|
* Implements the standard pattern used by all bridges:
|
||||||
* - Check if packet was seen before using _seen_packets.hasSeen()
|
* - Check if packet was seen before using _seen_packets.wasSeen()
|
||||||
* - Queue packet for mesh processing if not seen before
|
* - Queue packet for mesh processing if not seen before
|
||||||
* - Free packet if already seen to prevent duplicates
|
* - Free packet if already seen to prevent duplicates
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ void ESPNowBridge::begin() {
|
|||||||
// Initialize WiFi in station mode
|
// Initialize WiFi in station mode
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
|
|
||||||
// Set wifi channel
|
// Set Wi-Fi channel
|
||||||
if (esp_wifi_set_channel(_prefs->bridge_channel, WIFI_SECOND_CHAN_NONE) != ESP_OK) {
|
if (esp_wifi_set_channel(_prefs->bridge_channel, WIFI_SECOND_CHAN_NONE) != ESP_OK) {
|
||||||
BRIDGE_DEBUG_PRINTLN("Error setting WIFI channel to %d\n", _prefs->bridge_channel);
|
BRIDGE_DEBUG_PRINTLN("Error setting WIFI channel to %d\n", _prefs->bridge_channel);
|
||||||
return;
|
return;
|
||||||
@@ -167,7 +167,8 @@ void ESPNowBridge::sendPacket(mesh::Packet *packet) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_seen_packets.hasSeen(packet)) {
|
if (!_seen_packets.wasSeen(packet)) {
|
||||||
|
_seen_packets.markSeen(packet);
|
||||||
// Create a temporary buffer just for size calculation and reuse for actual writing
|
// Create a temporary buffer just for size calculation and reuse for actual writing
|
||||||
uint8_t sizingBuffer[MAX_PAYLOAD_SIZE];
|
uint8_t sizingBuffer[MAX_PAYLOAD_SIZE];
|
||||||
uint16_t meshPacketLen = packet->writeTo(sizingBuffer);
|
uint16_t meshPacketLen = packet->writeTo(sizingBuffer);
|
||||||
|
|||||||
@@ -115,7 +115,8 @@ void RS232Bridge::sendPacket(mesh::Packet *packet) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_seen_packets.hasSeen(packet)) {
|
if (!_seen_packets.wasSeen(packet)) {
|
||||||
|
_seen_packets.markSeen(packet);
|
||||||
|
|
||||||
uint8_t buffer[MAX_SERIAL_PACKET_SIZE];
|
uint8_t buffer[MAX_SERIAL_PACKET_SIZE];
|
||||||
uint16_t len = packet->writeTo(buffer + 4);
|
uint16_t len = packet->writeTo(buffer + 4);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
* These two functions do nothing for ESP-NOW, but are needed for the
|
* These two functions do nothing for ESP-NOW, but are needed for the
|
||||||
* Radio interface.
|
* Radio interface.
|
||||||
*/
|
*/
|
||||||
virtual void setRxBoostedGainMode(bool) { }
|
virtual bool setRxBoostedGainMode(bool) { }
|
||||||
virtual bool getRxBoostedGainMode() const { return false; }
|
virtual bool getRxBoostedGainMode() const { return false; }
|
||||||
|
|
||||||
uint32_t intID();
|
uint32_t intID();
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ public:
|
|||||||
|
|
||||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||||
|
|
||||||
void setRxBoostedGainMode(bool en) override {
|
bool setRxBoostedGainMode(bool en) override {
|
||||||
((CustomLLCC68 *)_radio)->setRxBoostedGainMode(en);
|
return ((CustomLLCC68 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||||
}
|
}
|
||||||
bool getRxBoostedGainMode() const override {
|
bool getRxBoostedGainMode() const override {
|
||||||
return ((CustomLLCC68 *)_radio)->getRxBoostedGainMode();
|
return ((CustomLLCC68 *)_radio)->getRxBoostedGainMode();
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ public:
|
|||||||
return rssi;
|
return rssi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t getEstAirtimeFor(int len_bytes) override {
|
||||||
|
auto airtime = RadioLibWrapper::getEstAirtimeFor(len_bytes);
|
||||||
|
return airtime < 200 ? 200 : airtime; // at least 200 millis
|
||||||
|
}
|
||||||
|
|
||||||
void onSendFinished() override {
|
void onSendFinished() override {
|
||||||
RadioLibWrapper::onSendFinished();
|
RadioLibWrapper::onSendFinished();
|
||||||
_radio->setPreambleLength(preambleLengthForSF(getSpreadingFactor())); // overcomes weird issues with small and big pkts
|
_radio->setPreambleLength(preambleLengthForSF(getSpreadingFactor())); // overcomes weird issues with small and big pkts
|
||||||
@@ -36,8 +41,8 @@ public:
|
|||||||
|
|
||||||
uint8_t getSpreadingFactor() const override { return ((CustomLR1110 *)_radio)->getSpreadingFactor(); }
|
uint8_t getSpreadingFactor() const override { return ((CustomLR1110 *)_radio)->getSpreadingFactor(); }
|
||||||
|
|
||||||
void setRxBoostedGainMode(bool en) override {
|
bool setRxBoostedGainMode(bool en) override {
|
||||||
((CustomLR1110 *)_radio)->setRxBoostedGainMode(en);
|
return ((CustomLR1110 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||||
}
|
}
|
||||||
bool getRxBoostedGainMode() const override {
|
bool getRxBoostedGainMode() const override {
|
||||||
return ((CustomLR1110 *)_radio)->getRxBoostedGainMode();
|
return ((CustomLR1110 *)_radio)->getRxBoostedGainMode();
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ public:
|
|||||||
|
|
||||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||||
|
|
||||||
void setRxBoostedGainMode(bool en) override {
|
bool setRxBoostedGainMode(bool en) override {
|
||||||
((CustomSX1262 *)_radio)->setRxBoostedGainMode(en);
|
return ((CustomSX1262 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||||
}
|
}
|
||||||
bool getRxBoostedGainMode() const override {
|
bool getRxBoostedGainMode() const override {
|
||||||
return ((CustomSX1262 *)_radio)->getRxBoostedGainMode();
|
return ((CustomSX1262 *)_radio)->getRxBoostedGainMode();
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ public:
|
|||||||
|
|
||||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||||
|
|
||||||
void setRxBoostedGainMode(bool en) override {
|
bool setRxBoostedGainMode(bool en) override {
|
||||||
((CustomSX1268 *)_radio)->setRxBoostedGainMode(en);
|
return ((CustomSX1268 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||||
}
|
}
|
||||||
bool getRxBoostedGainMode() const override {
|
bool getRxBoostedGainMode() const override {
|
||||||
return ((CustomSX1268 *)_radio)->getRxBoostedGainMode();
|
return ((CustomSX1268 *)_radio)->getRxBoostedGainMode();
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ void RadioLibWrapper::begin() {
|
|||||||
|
|
||||||
_noise_floor = 0;
|
_noise_floor = 0;
|
||||||
_threshold = 0;
|
_threshold = 0;
|
||||||
|
_cad_enabled = false;
|
||||||
|
|
||||||
// start average out some samples
|
// start average out some samples
|
||||||
_num_floor_samples = 0;
|
_num_floor_samples = 0;
|
||||||
@@ -178,10 +179,26 @@ void RadioLibWrapper::onSendFinished() {
|
|||||||
state = STATE_IDLE;
|
state = STATE_IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int16_t RadioLibWrapper::performChannelScan() {
|
||||||
|
return _radio->scanChannel();
|
||||||
|
}
|
||||||
|
|
||||||
bool RadioLibWrapper::isChannelActive() {
|
bool RadioLibWrapper::isChannelActive() {
|
||||||
return _threshold == 0
|
// int.thresh: RSSI-based interference detection (relative to noise floor)
|
||||||
? false // interference check is disabled
|
if (_threshold != 0 && getCurrentRSSI() > _noise_floor + _threshold) return true;
|
||||||
: getCurrentRSSI() > _noise_floor + _threshold;
|
|
||||||
|
// cad: hardware channel activity detection
|
||||||
|
if (_cad_enabled) {
|
||||||
|
int16_t result = performChannelScan();
|
||||||
|
// scanChannel() triggers DIO interrupt (CAD done) which sets STATE_INT_READY
|
||||||
|
// via setFlag() ISR. Clear it before restarting RX so recvRaw() doesn't
|
||||||
|
// try to read a non-existent packet and count a spurious recv error.
|
||||||
|
state = STATE_IDLE;
|
||||||
|
startRecv();
|
||||||
|
if (result != RADIOLIB_CHANNEL_FREE) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float RadioLibWrapper::getLastRSSI() const {
|
float RadioLibWrapper::getLastRSSI() const {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ protected:
|
|||||||
mesh::MainBoard* _board;
|
mesh::MainBoard* _board;
|
||||||
uint32_t n_recv, n_sent, n_recv_errors;
|
uint32_t n_recv, n_sent, n_recv_errors;
|
||||||
int16_t _noise_floor, _threshold;
|
int16_t _noise_floor, _threshold;
|
||||||
|
bool _cad_enabled;
|
||||||
uint16_t _num_floor_samples;
|
uint16_t _num_floor_samples;
|
||||||
int32_t _floor_sample_sum;
|
int32_t _floor_sample_sum;
|
||||||
uint8_t _preamble_sf;
|
uint8_t _preamble_sf;
|
||||||
@@ -46,9 +47,11 @@ public:
|
|||||||
virtual uint8_t getSpreadingFactor() const { return LORA_SF; }
|
virtual uint8_t getSpreadingFactor() const { return LORA_SF; }
|
||||||
static uint16_t preambleLengthForSF(uint8_t sf) { return sf <= 8 ? 32 : 16; }
|
static uint16_t preambleLengthForSF(uint8_t sf) { return sf <= 8 ? 32 : 16; }
|
||||||
void updatePreamble(uint8_t sf) { _preamble_sf = sf; _radio->setPreambleLength(preambleLengthForSF(sf)); }
|
void updatePreamble(uint8_t sf) { _preamble_sf = sf; _radio->setPreambleLength(preambleLengthForSF(sf)); }
|
||||||
|
virtual int16_t performChannelScan();
|
||||||
|
|
||||||
int getNoiseFloor() const override { return _noise_floor; }
|
int getNoiseFloor() const override { return _noise_floor; }
|
||||||
void triggerNoiseFloorCalibrate(int threshold) override;
|
void triggerNoiseFloorCalibrate(int threshold) override;
|
||||||
|
void setCADEnabled(bool enable) override { _cad_enabled = enable; }
|
||||||
void resetAGC() override;
|
void resetAGC() override;
|
||||||
|
|
||||||
void loop() override;
|
void loop() override;
|
||||||
@@ -63,7 +66,7 @@ public:
|
|||||||
|
|
||||||
float packetScore(float snr, int packet_len) override { return packetScoreInt(snr, 10, packet_len); } // assume sf=10
|
float packetScore(float snr, int packet_len) override { return packetScoreInt(snr, 10, packet_len); } // assume sf=10
|
||||||
|
|
||||||
virtual void setRxBoostedGainMode(bool) { }
|
virtual bool setRxBoostedGainMode(bool) { return false; }
|
||||||
virtual bool getRxBoostedGainMode() const { return false; }
|
virtual bool getRxBoostedGainMode() const { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ public:
|
|||||||
case LPP_GPS:
|
case LPP_GPS:
|
||||||
_pos += 9; break;
|
_pos += 9; break;
|
||||||
case LPP_POLYLINE:
|
case LPP_POLYLINE:
|
||||||
_pos += 8; break; // TODO: this is MINIMIUM
|
_pos += 8; break; // TODO: this is MINIMUM
|
||||||
case LPP_GYROMETER:
|
case LPP_GYROMETER:
|
||||||
case LPP_ACCELEROMETER:
|
case LPP_ACCELEROMETER:
|
||||||
_pos += 6; break;
|
_pos += 6; break;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ static int _internal_flash_read(const struct lfs_config *c, lfs_block_t block, l
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Program a region in a block. The block must have previously
|
// Program a region in a block. The block must have previously
|
||||||
// been erased. Negative error codes are propogated to the user.
|
// been erased. Negative error codes are propagated to the user.
|
||||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||||
static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
|
static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
|
||||||
{
|
{
|
||||||
@@ -62,7 +62,7 @@ static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, l
|
|||||||
|
|
||||||
// Erase a block. A block must be erased before being programmed.
|
// Erase a block. A block must be erased before being programmed.
|
||||||
// The state of an erased block is undefined. Negative error codes
|
// The state of an erased block is undefined. Negative error codes
|
||||||
// are propogated to the user.
|
// are propagated to the user.
|
||||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||||
static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block)
|
static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block)
|
||||||
{
|
{
|
||||||
@@ -87,7 +87,7 @@ static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sync the state of the underlying block device. Negative error codes
|
// Sync the state of the underlying block device. Negative error codes
|
||||||
// are propogated to the user.
|
// are propagated to the user.
|
||||||
static int _internal_flash_sync(const struct lfs_config *c)
|
static int _internal_flash_sync(const struct lfs_config *c)
|
||||||
{
|
{
|
||||||
return LFS_ERR_OK; // don't need sync
|
return LFS_ERR_OK; // don't need sync
|
||||||
|
|||||||
@@ -1166,7 +1166,7 @@ char DefaultFontTableLookup(const uint8_t ch) {
|
|||||||
uint8_t last = LASTCHAR; // get last char
|
uint8_t last = LASTCHAR; // get last char
|
||||||
LASTCHAR = ch;
|
LASTCHAR = ch;
|
||||||
|
|
||||||
switch (last) { // conversion depnding on first UTF8-character
|
switch (last) { // conversion depending on first UTF8-character
|
||||||
case 0xC2: return (uint8_t) ch;
|
case 0xC2: return (uint8_t) ch;
|
||||||
case 0xC3: return (uint8_t) (ch | 0xC0);
|
case 0xC3: return (uint8_t) (ch | 0xC0);
|
||||||
case 0x82: if (ch == 0xAC) return (uint8_t) 0x80; // special case Euro-symbol
|
case 0x82: if (ch == 0xAC) return (uint8_t) 0x80; // special case Euro-symbol
|
||||||
|
|||||||
+25
-4
@@ -3,12 +3,33 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
// Mock SHA256 class for testing
|
// Mock SHA256 for native testing — deterministic but not cryptographic.
|
||||||
// Provides minimal interface to allow Utils.cpp to compile
|
// finalize() writes real (non-garbage) output so calculatePacketHash() produces
|
||||||
|
// distinguishable results for packets with different payloads.
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
class SHA256 {
|
class SHA256 {
|
||||||
|
uint8_t _state[32];
|
||||||
|
size_t _len;
|
||||||
public:
|
public:
|
||||||
void update(const uint8_t* data, size_t len) {}
|
SHA256() : _len(0) { memset(_state, 0, sizeof(_state)); }
|
||||||
void finalize(uint8_t* hash, size_t hashLen) {}
|
|
||||||
|
void update(const void* data, size_t len) {
|
||||||
|
const uint8_t* bytes = static_cast<const uint8_t*>(data);
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
uint8_t b = bytes[i];
|
||||||
|
_state[_len % 32] ^= b;
|
||||||
|
_state[(_len + 1) % 32] += (uint8_t)((b >> 1) | (b << 7));
|
||||||
|
_len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void finalize(uint8_t* hash, size_t hashLen) {
|
||||||
|
for (size_t i = 0; i < hashLen; i++) {
|
||||||
|
hash[i] = _state[i % 32];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void resetHMAC(const uint8_t* key, size_t keyLen) {}
|
void resetHMAC(const uint8_t* key, size_t keyLen) {}
|
||||||
void finalizeHMAC(const uint8_t* key, size_t keyLen, uint8_t* hash, size_t hashLen) {}
|
void finalizeHMAC(const uint8_t* key, size_t keyLen, uint8_t* hash, size_t hashLen) {}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "helpers/SimpleMeshTables.h"
|
||||||
|
|
||||||
|
using namespace mesh;
|
||||||
|
|
||||||
|
// Build a packet that calculatePacketHash() distinguishes by payload content.
|
||||||
|
// header selects ROUTE_TYPE_FLOOD so isRouteDirect() returns false.
|
||||||
|
static Packet makeFloodPacket(uint8_t seed) {
|
||||||
|
Packet p;
|
||||||
|
p.header = ROUTE_TYPE_FLOOD | (PAYLOAD_TYPE_ACK << PH_TYPE_SHIFT);
|
||||||
|
p.payload[0] = seed;
|
||||||
|
p.payload_len = 1;
|
||||||
|
p.path_len = 0;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Packet makeDirectPacket(uint8_t seed) {
|
||||||
|
Packet p;
|
||||||
|
p.header = ROUTE_TYPE_DIRECT | (PAYLOAD_TYPE_ACK << PH_TYPE_SHIFT);
|
||||||
|
p.payload[0] = seed;
|
||||||
|
p.payload_len = 1;
|
||||||
|
p.path_len = 0;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── wasSeen: pure query ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
TEST(SimpleMeshTables, WasSeen_ReturnsFalseForUnseen) {
|
||||||
|
SimpleMeshTables t;
|
||||||
|
Packet p = makeFloodPacket(0x01);
|
||||||
|
EXPECT_FALSE(t.wasSeen(&p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// wasSeen shouldn't change state
|
||||||
|
TEST(SimpleMeshTables, WasSeen_IsPureQuery_DoesNotInsert) {
|
||||||
|
SimpleMeshTables t;
|
||||||
|
Packet p = makeFloodPacket(0x01);
|
||||||
|
EXPECT_FALSE(t.wasSeen(&p));
|
||||||
|
EXPECT_FALSE(t.wasSeen(&p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── markSeen + wasSeen ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
TEST(SimpleMeshTables, MarkSeen_MakesWasSeenReturnTrue) {
|
||||||
|
SimpleMeshTables t;
|
||||||
|
Packet p = makeFloodPacket(0x01);
|
||||||
|
t.markSeen(&p);
|
||||||
|
EXPECT_TRUE(t.wasSeen(&p));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SimpleMeshTables, MarkSeen_DoesNotAffectOtherPackets) {
|
||||||
|
SimpleMeshTables t;
|
||||||
|
Packet p1 = makeFloodPacket(0x01);
|
||||||
|
Packet p2 = makeFloodPacket(0x02);
|
||||||
|
t.markSeen(&p1);
|
||||||
|
EXPECT_FALSE(t.wasSeen(&p2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Canonical pattern used at every onRecvPacket call site:
|
||||||
|
// if (!wasSeen(pkt)) { markSeen(pkt); process(pkt); }
|
||||||
|
TEST(SimpleMeshTables, QueryThenMark_WorksCorrectly) {
|
||||||
|
SimpleMeshTables t;
|
||||||
|
Packet p = makeFloodPacket(0x01);
|
||||||
|
EXPECT_FALSE(t.wasSeen(&p));
|
||||||
|
t.markSeen(&p);
|
||||||
|
EXPECT_TRUE(t.wasSeen(&p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── dup stats ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
TEST(SimpleMeshTables, WasSeen_IncrementsFloodDupStat) {
|
||||||
|
SimpleMeshTables t;
|
||||||
|
Packet p = makeFloodPacket(0x01);
|
||||||
|
t.markSeen(&p);
|
||||||
|
t.wasSeen(&p);
|
||||||
|
EXPECT_EQ(1u, t.getNumFloodDups());
|
||||||
|
EXPECT_EQ(0u, t.getNumDirectDups());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SimpleMeshTables, WasSeen_IncrementsDirectDupStat) {
|
||||||
|
SimpleMeshTables t;
|
||||||
|
Packet p = makeDirectPacket(0x01);
|
||||||
|
t.markSeen(&p);
|
||||||
|
t.wasSeen(&p);
|
||||||
|
EXPECT_EQ(0u, t.getNumFloodDups());
|
||||||
|
EXPECT_EQ(1u, t.getNumDirectDups());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── clear ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
TEST(SimpleMeshTables, Clear_RemovesSeenPacket) {
|
||||||
|
SimpleMeshTables t;
|
||||||
|
Packet p = makeFloodPacket(0x01);
|
||||||
|
t.markSeen(&p);
|
||||||
|
ASSERT_TRUE(t.wasSeen(&p));
|
||||||
|
t.clear(&p);
|
||||||
|
EXPECT_FALSE(t.wasSeen(&p));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
[Heltec_mesh_solar]
|
[Heltec_mesh_solar]
|
||||||
extends = nrf52_base
|
extends = nrf52_base
|
||||||
board = heltec_mesh_solar
|
board = heltec_mesh_solar
|
||||||
platform_packages = framework-arduinoadafruitnrf52
|
|
||||||
board_build.ldscript = boards/nrf52840_s140_v6.ld
|
board_build.ldscript = boards/nrf52840_s140_v6.ld
|
||||||
build_flags = ${nrf52_base.build_flags}
|
build_flags = ${nrf52_base.build_flags}
|
||||||
-I src/helpers/nrf52
|
-I src/helpers/nrf52
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ class LoRaFEMControl
|
|||||||
void setRxModeEnable(void);
|
void setRxModeEnable(void);
|
||||||
void setRxModeEnableWhenMCUSleep(void);
|
void setRxModeEnableWhenMCUSleep(void);
|
||||||
void setLNAEnable(bool enabled);
|
void setLNAEnable(bool enabled);
|
||||||
bool isLnaCanControl(void) { return lna_can_control; }
|
bool isLnaCanControl(void) const { return lna_can_control; }
|
||||||
void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
|
void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
|
||||||
|
bool isLNAEnabled(void) const { return lna_enabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool lna_enabled = false;
|
bool lna_enabled = false;
|
||||||
|
|||||||
@@ -124,3 +124,21 @@ void T096Board::powerOff() {
|
|||||||
const char* T096Board::getManufacturerName() const {
|
const char* T096Board::getManufacturerName() const {
|
||||||
return "Heltec T096";
|
return "Heltec T096";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool T096Board::setLoRaFemLnaEnabled(bool enable) {
|
||||||
|
if (!loRaFEMControl.isLnaCanControl()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
loRaFEMControl.setLNAEnable(enable);
|
||||||
|
loRaFEMControl.setRxModeEnable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool T096Board::canControlLoRaFemLna() const {
|
||||||
|
return loRaFEMControl.isLnaCanControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool T096Board::isLoRaFemLnaEnabled() const {
|
||||||
|
return loRaFEMControl.isLNAEnabled();
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,4 +25,7 @@ public:
|
|||||||
uint16_t getBattMilliVolts() override;
|
uint16_t getBattMilliVolts() override;
|
||||||
const char* getManufacturerName() const override ;
|
const char* getManufacturerName() const override ;
|
||||||
void powerOff() override;
|
void powerOff() override;
|
||||||
|
bool setLoRaFemLnaEnabled(bool enable) override;
|
||||||
|
bool canControlLoRaFemLna() const override;
|
||||||
|
bool isLoRaFemLnaEnabled() const override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
|||||||
|
|
||||||
#if ENV_INCLUDE_GPS
|
#if ENV_INCLUDE_GPS
|
||||||
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
||||||
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
|
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock);
|
||||||
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
|
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
|
||||||
#else
|
#else
|
||||||
EnvironmentSensorManager sensors;
|
EnvironmentSensorManager sensors;
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#include "HeltecTowerV2Board.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
extern void variant_shutdown();
|
||||||
|
|
||||||
|
#ifdef NRF52_POWER_MANAGEMENT
|
||||||
|
const PowerMgtConfig power_config = {
|
||||||
|
.lpcomp_ain_channel = PWRMGT_LPCOMP_AIN,
|
||||||
|
.lpcomp_refsel = PWRMGT_LPCOMP_REFSEL,
|
||||||
|
.voltage_bootlock = PWRMGT_VOLTAGE_BOOTLOCK
|
||||||
|
};
|
||||||
|
|
||||||
|
void HeltecTowerV2Board::initiateShutdown(uint8_t reason) {
|
||||||
|
pinMode(PIN_GPS_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
|
||||||
|
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_STANDBY, LOW);
|
||||||
|
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE);
|
||||||
|
loRaFEMControl.setSleepModeEnable();
|
||||||
|
|
||||||
|
bool enable_lpcomp = (reason == SHUTDOWN_REASON_LOW_VOLTAGE ||
|
||||||
|
reason == SHUTDOWN_REASON_BOOT_PROTECT);
|
||||||
|
pinMode(PIN_BAT_CTL, OUTPUT);
|
||||||
|
digitalWrite(PIN_BAT_CTL, enable_lpcomp ? HIGH : LOW);
|
||||||
|
|
||||||
|
if (enable_lpcomp) {
|
||||||
|
configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel);
|
||||||
|
}
|
||||||
|
|
||||||
|
variant_shutdown();
|
||||||
|
enterSystemOff(reason);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void HeltecTowerV2Board::begin() {
|
||||||
|
NRF52Board::begin();
|
||||||
|
|
||||||
|
pinMode(P_LORA_TX_LED, OUTPUT);
|
||||||
|
digitalWrite(P_LORA_TX_LED, !LED_STATE_ON);
|
||||||
|
|
||||||
|
pinMode(PIN_BAT_CTL, OUTPUT);
|
||||||
|
digitalWrite(PIN_BAT_CTL, LOW);
|
||||||
|
|
||||||
|
#ifdef NRF52_POWER_MANAGEMENT
|
||||||
|
checkBootVoltage(&power_config);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
|
||||||
|
Wire.begin();
|
||||||
|
|
||||||
|
pinMode(PIN_GPS_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
|
||||||
|
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE);
|
||||||
|
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_STANDBY, HIGH);
|
||||||
|
loRaFEMControl.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeltecTowerV2Board::onBeforeTransmit() {
|
||||||
|
digitalWrite(P_LORA_TX_LED, LED_STATE_ON);
|
||||||
|
loRaFEMControl.setTxModeEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeltecTowerV2Board::onAfterTransmit() {
|
||||||
|
digitalWrite(P_LORA_TX_LED, !LED_STATE_ON);
|
||||||
|
loRaFEMControl.setRxModeEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t HeltecTowerV2Board::getBattMilliVolts() {
|
||||||
|
analogReadResolution(12);
|
||||||
|
analogReference(VBAT_AR_INTERNAL);
|
||||||
|
pinMode(PIN_VBAT_READ, INPUT);
|
||||||
|
pinMode(PIN_BAT_CTL, OUTPUT);
|
||||||
|
digitalWrite(PIN_BAT_CTL, HIGH);
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
int adcvalue = analogRead(PIN_VBAT_READ);
|
||||||
|
digitalWrite(PIN_BAT_CTL, LOW);
|
||||||
|
|
||||||
|
return (uint16_t)((float)adcvalue * MV_LSB * ADC_MULTIPLIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* HeltecTowerV2Board::getManufacturerName() const {
|
||||||
|
return "Heltec Tower V2";
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeltecTowerV2Board::powerOff() {
|
||||||
|
pinMode(PIN_GPS_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
|
||||||
|
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_STANDBY, LOW);
|
||||||
|
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE);
|
||||||
|
loRaFEMControl.setSleepModeEnable();
|
||||||
|
pinMode(PIN_BAT_CTL, OUTPUT);
|
||||||
|
digitalWrite(PIN_BAT_CTL, LOW);
|
||||||
|
variant_shutdown();
|
||||||
|
sd_power_system_off();
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <MeshCore.h>
|
||||||
|
#include <helpers/NRF52Board.h>
|
||||||
|
#include "LoRaFEMControl.h"
|
||||||
|
|
||||||
|
class HeltecTowerV2Board : public NRF52BoardDCDC {
|
||||||
|
protected:
|
||||||
|
#ifdef NRF52_POWER_MANAGEMENT
|
||||||
|
void initiateShutdown(uint8_t reason) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
LoRaFEMControl loRaFEMControl;
|
||||||
|
|
||||||
|
HeltecTowerV2Board() : NRF52Board("TOWER_V2_OTA") {}
|
||||||
|
void begin();
|
||||||
|
void onBeforeTransmit() override;
|
||||||
|
void onAfterTransmit() override;
|
||||||
|
uint16_t getBattMilliVolts() override;
|
||||||
|
const char* getManufacturerName() const override;
|
||||||
|
void powerOff() override;
|
||||||
|
};
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "LoRaFEMControl.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "variant.h"
|
||||||
|
|
||||||
|
static void enableFEMPower() {
|
||||||
|
bool wasOff = digitalRead(LORA_KCT8103L_EN) != HIGH;
|
||||||
|
digitalWrite(LORA_KCT8103L_EN, HIGH);
|
||||||
|
if (wasOff) {
|
||||||
|
delay(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaFEMControl::init() {
|
||||||
|
pinMode(LORA_KCT8103L_EN, OUTPUT);
|
||||||
|
digitalWrite(LORA_KCT8103L_EN, HIGH);
|
||||||
|
delay(1);
|
||||||
|
pinMode(LORA_KCT8103L_TX_RX, OUTPUT);
|
||||||
|
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaFEMControl::setSleepModeEnable() {
|
||||||
|
pinMode(LORA_KCT8103L_EN, OUTPUT);
|
||||||
|
digitalWrite(LORA_KCT8103L_EN, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaFEMControl::setTxModeEnable() {
|
||||||
|
enableFEMPower();
|
||||||
|
digitalWrite(LORA_KCT8103L_TX_RX, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaFEMControl::setRxModeEnable() {
|
||||||
|
enableFEMPower();
|
||||||
|
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaFEMControl::setRxModeEnableWhenMCUSleep() {
|
||||||
|
enableFEMPower();
|
||||||
|
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class LoRaFEMControl {
|
||||||
|
public:
|
||||||
|
LoRaFEMControl() {}
|
||||||
|
virtual ~LoRaFEMControl() {}
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void setSleepModeEnable();
|
||||||
|
void setTxModeEnable();
|
||||||
|
void setRxModeEnable();
|
||||||
|
void setRxModeEnableWhenMCUSleep();
|
||||||
|
};
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
[Heltec_tower_v2]
|
||||||
|
extends = nrf52_base
|
||||||
|
board = heltec_tower_v2
|
||||||
|
board_build.ldscript = boards/nrf52840_s140_v6.ld
|
||||||
|
build_flags = ${nrf52_base.build_flags}
|
||||||
|
-D ENV_INCLUDE_GPS=1
|
||||||
|
-I lib/nrf52/s140_nrf52_6.1.1_API/include
|
||||||
|
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
|
||||||
|
-I variants/heltec_tower_v2
|
||||||
|
-D HELTEC_TOWER_V2
|
||||||
|
-D NRF52_POWER_MANAGEMENT
|
||||||
|
-D RADIO_CLASS=CustomSX1262
|
||||||
|
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
||||||
|
-D LORA_TX_POWER=12
|
||||||
|
-D MAX_LORA_TX_POWER=22 ; Max SX1262 output -> ~29dBm at antenna
|
||||||
|
-D SX126X_CURRENT_LIMIT=140
|
||||||
|
-D SX126X_RX_BOOSTED_GAIN=1
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter}
|
||||||
|
+<helpers/*.cpp>
|
||||||
|
+<helpers/sensors>
|
||||||
|
+<../variants/heltec_tower_v2>
|
||||||
|
lib_deps =
|
||||||
|
${nrf52_base.lib_deps}
|
||||||
|
stevemarple/MicroNMEA @ ^2.0.6
|
||||||
|
debug_tool = jlink
|
||||||
|
upload_protocol = nrfutil
|
||||||
|
|
||||||
|
[env:Heltec_tower_v2_repeater]
|
||||||
|
extends = Heltec_tower_v2
|
||||||
|
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||||
|
+<../examples/simple_repeater>
|
||||||
|
build_flags =
|
||||||
|
${Heltec_tower_v2.build_flags}
|
||||||
|
-D ADVERT_NAME='"Heltec_Tower_V2 Repeater"'
|
||||||
|
-D ADVERT_LAT=0.0
|
||||||
|
-D ADVERT_LON=0.0
|
||||||
|
-D ADMIN_PASSWORD='"password"'
|
||||||
|
-D MAX_NEIGHBOURS=50
|
||||||
|
; -D MESH_PACKET_LOGGING=1
|
||||||
|
; -D MESH_DEBUG=1
|
||||||
|
|
||||||
|
[env:Heltec_tower_v2_room_server]
|
||||||
|
extends = Heltec_tower_v2
|
||||||
|
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||||
|
+<../examples/simple_room_server>
|
||||||
|
build_flags =
|
||||||
|
${Heltec_tower_v2.build_flags}
|
||||||
|
-D ADVERT_NAME='"Heltec_Tower_V2 Room"'
|
||||||
|
-D ADVERT_LAT=0.0
|
||||||
|
-D ADVERT_LON=0.0
|
||||||
|
-D ADMIN_PASSWORD='"password"'
|
||||||
|
-D ROOM_PASSWORD='"hello"'
|
||||||
|
; -D MESH_PACKET_LOGGING=1
|
||||||
|
; -D MESH_DEBUG=1
|
||||||
|
|
||||||
|
[env:Heltec_tower_v2_companion_radio_ble]
|
||||||
|
extends = Heltec_tower_v2
|
||||||
|
board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld
|
||||||
|
board_upload.maximum_size = 712704
|
||||||
|
build_flags =
|
||||||
|
${Heltec_tower_v2.build_flags}
|
||||||
|
-I examples/companion_radio/ui-new
|
||||||
|
-D DISPLAY_CLASS=NullDisplayDriver
|
||||||
|
-D MAX_CONTACTS=350
|
||||||
|
-D MAX_GROUP_CHANNELS=40
|
||||||
|
-D BLE_PIN_CODE=123456
|
||||||
|
; -D BLE_DEBUG_LOGGING=1
|
||||||
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
|
; -D MESH_PACKET_LOGGING=1
|
||||||
|
; -D MESH_DEBUG=1
|
||||||
|
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||||
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
|
+<../examples/companion_radio/*.cpp>
|
||||||
|
+<../examples/companion_radio/ui-new/*.cpp>
|
||||||
|
lib_deps =
|
||||||
|
${Heltec_tower_v2.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
|
[env:Heltec_tower_v2_companion_radio_usb]
|
||||||
|
extends = Heltec_tower_v2
|
||||||
|
board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld
|
||||||
|
board_upload.maximum_size = 712704
|
||||||
|
build_flags =
|
||||||
|
${Heltec_tower_v2.build_flags}
|
||||||
|
-I examples/companion_radio/ui-new
|
||||||
|
-D DISPLAY_CLASS=NullDisplayDriver
|
||||||
|
-D MAX_CONTACTS=350
|
||||||
|
-D MAX_GROUP_CHANNELS=40
|
||||||
|
; -D BLE_PIN_CODE=123456
|
||||||
|
; -D BLE_DEBUG_LOGGING=1
|
||||||
|
; -D MESH_PACKET_LOGGING=1
|
||||||
|
; -D MESH_DEBUG=1
|
||||||
|
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||||
|
+<helpers/nrf52/*.cpp>
|
||||||
|
+<../examples/companion_radio/*.cpp>
|
||||||
|
+<../examples/companion_radio/ui-new/*.cpp>
|
||||||
|
lib_deps =
|
||||||
|
${Heltec_tower_v2.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
|
[env:Heltec_tower_v2_kiss_modem]
|
||||||
|
extends = Heltec_tower_v2
|
||||||
|
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||||
|
+<../examples/kiss_modem/>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <helpers/ArduinoHelpers.h>
|
||||||
|
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
||||||
|
|
||||||
|
HeltecTowerV2Board board;
|
||||||
|
|
||||||
|
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
|
||||||
|
|
||||||
|
WRAPPER_CLASS radio_driver(radio, board);
|
||||||
|
|
||||||
|
VolatileRTCClock fallback_clock;
|
||||||
|
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||||
|
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock);
|
||||||
|
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
|
||||||
|
|
||||||
|
#ifdef DISPLAY_CLASS
|
||||||
|
DISPLAY_CLASS display;
|
||||||
|
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool radio_init() {
|
||||||
|
rtc_clock.begin(Wire);
|
||||||
|
return radio.std_init(&SPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh::LocalIdentity radio_new_identity() {
|
||||||
|
RadioNoiseListener rng(radio);
|
||||||
|
return mesh::LocalIdentity(&rng);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define RADIOLIB_STATIC_ONLY 1
|
||||||
|
#include <RadioLib.h>
|
||||||
|
#include <HeltecTowerV2Board.h>
|
||||||
|
#include <helpers/AutoDiscoverRTCClock.h>
|
||||||
|
#include <helpers/radiolib/CustomSX1262Wrapper.h>
|
||||||
|
#include <helpers/radiolib/RadioLibWrappers.h>
|
||||||
|
#include <helpers/sensors/EnvironmentSensorManager.h>
|
||||||
|
#include <helpers/sensors/LocationProvider.h>
|
||||||
|
|
||||||
|
#ifdef DISPLAY_CLASS
|
||||||
|
#include <helpers/ui/MomentaryButton.h>
|
||||||
|
#include "helpers/ui/NullDisplayDriver.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern HeltecTowerV2Board board;
|
||||||
|
extern WRAPPER_CLASS radio_driver;
|
||||||
|
extern AutoDiscoverRTCClock rtc_clock;
|
||||||
|
extern EnvironmentSensorManager sensors;
|
||||||
|
|
||||||
|
#ifdef DISPLAY_CLASS
|
||||||
|
extern DISPLAY_CLASS display;
|
||||||
|
extern MomentaryButton user_btn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool radio_init();
|
||||||
|
mesh::LocalIdentity radio_new_identity();
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#include "variant.h"
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "nrf.h"
|
||||||
|
#include "wiring_constants.h"
|
||||||
|
#include "wiring_digital.h"
|
||||||
|
|
||||||
|
const uint32_t g_ADigitalPinMap[] = {
|
||||||
|
0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
|
||||||
|
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
40, 41, 42, 43, 44, 45, 46, 47
|
||||||
|
};
|
||||||
|
|
||||||
|
void initVariant()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void variant_shutdown()
|
||||||
|
{
|
||||||
|
nrf_gpio_cfg_default(PIN_GPS_EN);
|
||||||
|
nrf_gpio_cfg_default(PIN_GPS_PPS);
|
||||||
|
nrf_gpio_cfg_default(PIN_GPS_RESET);
|
||||||
|
nrf_gpio_cfg_default(PIN_GPS_STANDBY);
|
||||||
|
nrf_gpio_cfg_default(GPS_RX_PIN);
|
||||||
|
nrf_gpio_cfg_default(GPS_TX_PIN);
|
||||||
|
pinMode(LORA_KCT8103L_EN, OUTPUT);
|
||||||
|
digitalWrite(LORA_KCT8103L_EN, LOW);
|
||||||
|
nrf_gpio_cfg_default(LORA_KCT8103L_TX_RX);
|
||||||
|
nrf_gpio_cfg_default(RF_PA_DETECT_PIN);
|
||||||
|
nrf_gpio_cfg_default(SX126X_CS);
|
||||||
|
nrf_gpio_cfg_default(SX126X_DIO1);
|
||||||
|
nrf_gpio_cfg_default(SX126X_BUSY);
|
||||||
|
nrf_gpio_cfg_default(SX126X_RESET);
|
||||||
|
nrf_gpio_cfg_default(PIN_SPI_MISO);
|
||||||
|
nrf_gpio_cfg_default(PIN_SPI_MOSI);
|
||||||
|
nrf_gpio_cfg_default(PIN_SPI_SCK);
|
||||||
|
nrf_gpio_cfg_default(PIN_LED);
|
||||||
|
detachInterrupt(PIN_GPS_PPS);
|
||||||
|
detachInterrupt(PIN_BUTTON1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WVariant.h"
|
||||||
|
|
||||||
|
#define USE_LFXO
|
||||||
|
#define VARIANT_MCK (64000000ul)
|
||||||
|
|
||||||
|
#define PINS_COUNT (48)
|
||||||
|
#define NUM_DIGITAL_PINS (48)
|
||||||
|
#define NUM_ANALOG_INPUTS (1)
|
||||||
|
#define NUM_ANALOG_OUTPUTS (0)
|
||||||
|
|
||||||
|
#define WIRE_INTERFACES_COUNT (1)
|
||||||
|
#define PIN_WIRE_SDA (0 + 30)
|
||||||
|
#define PIN_WIRE_SCL (0 + 5)
|
||||||
|
#define PIN_BOARD_SDA PIN_WIRE_SDA
|
||||||
|
#define PIN_BOARD_SCL PIN_WIRE_SCL
|
||||||
|
|
||||||
|
#define SPI_INTERFACES_COUNT (1)
|
||||||
|
#define PIN_SPI_MISO (0 + 23)
|
||||||
|
#define PIN_SPI_MOSI (0 + 22)
|
||||||
|
#define PIN_SPI_SCK (0 + 19)
|
||||||
|
#define PIN_SPI_NSS LORA_CS
|
||||||
|
|
||||||
|
#define LED_BUILTIN (32 + 15)
|
||||||
|
#define PIN_LED LED_BUILTIN
|
||||||
|
#define LED_RED (-1)
|
||||||
|
#define LED_GREEN (-1)
|
||||||
|
#define LED_BLUE (-1)
|
||||||
|
#define LED_PIN (-1)
|
||||||
|
#define P_LORA_TX_LED LED_BUILTIN
|
||||||
|
#define LED_STATE_ON LOW
|
||||||
|
|
||||||
|
#define PIN_BUTTON1 (32 + 10)
|
||||||
|
#define BUTTON_PIN PIN_BUTTON1
|
||||||
|
#define PIN_USER_BTN BUTTON_PIN
|
||||||
|
|
||||||
|
#define USE_SX1262
|
||||||
|
#define SX126X_CS (0 + 24)
|
||||||
|
#define LORA_CS SX126X_CS
|
||||||
|
#define SX126X_DIO1 (0 + 20)
|
||||||
|
#define SX126X_BUSY (0 + 17)
|
||||||
|
#define SX126X_RESET (0 + 25)
|
||||||
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
|
||||||
|
#define P_LORA_NSS LORA_CS
|
||||||
|
#define P_LORA_DIO_1 SX126X_DIO1
|
||||||
|
#define P_LORA_BUSY SX126X_BUSY
|
||||||
|
#define P_LORA_RESET SX126X_RESET
|
||||||
|
#define P_LORA_MISO PIN_SPI_MISO
|
||||||
|
#define P_LORA_MOSI PIN_SPI_MOSI
|
||||||
|
#define P_LORA_SCLK PIN_SPI_SCK
|
||||||
|
|
||||||
|
#define USE_KCT8103L_PA_ONLY
|
||||||
|
#define LORA_KCT8103L_EN (0 + 15)
|
||||||
|
#define LORA_KCT8103L_TX_RX (0 + 16)
|
||||||
|
#define LORA_PA_POWER LORA_KCT8103L_EN
|
||||||
|
#define RF_PA_DETECT_PIN (0 + 13)
|
||||||
|
#define RF_PA_HIGH_POWER_VALUE HIGH
|
||||||
|
|
||||||
|
#define GPS_L76K
|
||||||
|
#define GPS_RESET_MODE LOW
|
||||||
|
#define PIN_GPS_RESET (32 + 6)
|
||||||
|
#define PIN_GPS_RESET_ACTIVE GPS_RESET_MODE
|
||||||
|
#define PIN_GPS_EN (0 + 7)
|
||||||
|
#define PIN_GPS_EN_ACTIVE LOW
|
||||||
|
#define GPS_EN_ACTIVE PIN_GPS_EN_ACTIVE
|
||||||
|
#define PIN_GPS_STANDBY (32 + 2)
|
||||||
|
#define PIN_GPS_PPS (32 + 4)
|
||||||
|
#define GPS_BAUD_RATE 9600
|
||||||
|
|
||||||
|
// Upstream names are from the GPS perspective. MeshCore's PIN_GPS_TX is the
|
||||||
|
// CPU RX pin because EnvironmentSensorManager passes it as Serial1 RX.
|
||||||
|
#define GPS_TX_PIN (32 + 7)
|
||||||
|
#define GPS_RX_PIN (32 + 5)
|
||||||
|
#define PIN_GPS_TX GPS_RX_PIN
|
||||||
|
#define PIN_GPS_RX GPS_TX_PIN
|
||||||
|
|
||||||
|
#define PIN_SERIAL1_RX PIN_GPS_TX
|
||||||
|
#define PIN_SERIAL1_TX PIN_GPS_RX
|
||||||
|
#define PIN_SERIAL2_RX (-1)
|
||||||
|
#define PIN_SERIAL2_TX (-1)
|
||||||
|
|
||||||
|
#define HAS_HARDWARE_WATCHDOG
|
||||||
|
#define HARDWARE_WATCHDOG_DONE (0 + 9)
|
||||||
|
#define HARDWARE_WATCHDOG_WAKE (0 + 10)
|
||||||
|
#define HARDWARE_WATCHDOG_TIMEOUT_MS (8 * 60 * 1000)
|
||||||
|
|
||||||
|
#define SERIAL_PRINT_PORT 0
|
||||||
|
|
||||||
|
#define PIN_BAT_CTL (0 + 21)
|
||||||
|
#define ADC_CTRL PIN_BAT_CTL
|
||||||
|
#define ADC_CTRL_ENABLED HIGH
|
||||||
|
#define BATTERY_PIN (0 + 4)
|
||||||
|
#define PIN_VBAT_READ BATTERY_PIN
|
||||||
|
#define ADC_RESOLUTION 14
|
||||||
|
#define BATTERY_SENSE_RESOLUTION_BITS 12
|
||||||
|
#define BATTERY_SENSE_RESOLUTION 4096.0
|
||||||
|
#define AREF_VOLTAGE 3.0
|
||||||
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
|
#define ADC_MULTIPLIER (4.916F)
|
||||||
|
#define MV_LSB (3000.0F / 4096.0F)
|
||||||
|
|
||||||
|
#define NRF52_POWER_MANAGEMENT
|
||||||
|
#define PWRMGT_VOLTAGE_BOOTLOCK 3100
|
||||||
|
#define PWRMGT_LPCOMP_AIN 2
|
||||||
|
#define PWRMGT_LPCOMP_REFSEL 1
|
||||||
@@ -82,3 +82,21 @@ void HeltecTrackerV2Board::begin() {
|
|||||||
const char* HeltecTrackerV2Board::getManufacturerName() const {
|
const char* HeltecTrackerV2Board::getManufacturerName() const {
|
||||||
return "Heltec Tracker V2";
|
return "Heltec Tracker V2";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HeltecTrackerV2Board::setLoRaFemLnaEnabled(bool enable) {
|
||||||
|
if (!loRaFEMControl.isLnaCanControl()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
loRaFEMControl.setLNAEnable(enable);
|
||||||
|
loRaFEMControl.setRxModeEnable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HeltecTrackerV2Board::canControlLoRaFemLna() const {
|
||||||
|
return loRaFEMControl.isLnaCanControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HeltecTrackerV2Board::isLoRaFemLnaEnabled() const {
|
||||||
|
return loRaFEMControl.isLNAEnabled();
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,5 +21,8 @@ public:
|
|||||||
void powerOff() override;
|
void powerOff() override;
|
||||||
uint16_t getBattMilliVolts() override;
|
uint16_t getBattMilliVolts() override;
|
||||||
const char* getManufacturerName() const override ;
|
const char* getManufacturerName() const override ;
|
||||||
|
bool setLoRaFemLnaEnabled(bool enable) override;
|
||||||
|
bool canControlLoRaFemLna() const override;
|
||||||
|
bool isLoRaFemLnaEnabled() const override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ class LoRaFEMControl
|
|||||||
void setRxModeEnable(void);
|
void setRxModeEnable(void);
|
||||||
void setRxModeEnableWhenMCUSleep(void);
|
void setRxModeEnableWhenMCUSleep(void);
|
||||||
void setLNAEnable(bool enabled);
|
void setLNAEnable(bool enabled);
|
||||||
bool isLnaCanControl(void) { return lna_can_control; }
|
bool isLnaCanControl(void) const { return lna_can_control; }
|
||||||
void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
|
void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
|
||||||
|
bool isLNAEnabled(void) const { return lna_enabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool lna_enabled = false;
|
bool lna_enabled = false;
|
||||||
|
|||||||
@@ -83,3 +83,21 @@ void HeltecV4Board::begin() {
|
|||||||
return loRaFEMControl.getFEMType() == KCT8103L_PA ? "Heltec V4.3 OLED" : "Heltec V4 OLED";
|
return loRaFEMControl.getFEMType() == KCT8103L_PA ? "Heltec V4.3 OLED" : "Heltec V4 OLED";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HeltecV4Board::setLoRaFemLnaEnabled(bool enable) {
|
||||||
|
if (!loRaFEMControl.isLnaCanControl()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
loRaFEMControl.setLNAEnable(enable);
|
||||||
|
loRaFEMControl.setRxModeEnable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HeltecV4Board::canControlLoRaFemLna() const {
|
||||||
|
return loRaFEMControl.isLnaCanControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HeltecV4Board::isLoRaFemLnaEnabled() const {
|
||||||
|
return loRaFEMControl.isLNAEnabled();
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ public:
|
|||||||
void onAfterTransmit(void) override;
|
void onAfterTransmit(void) override;
|
||||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1);
|
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1);
|
||||||
void powerOff() override;
|
void powerOff() override;
|
||||||
|
bool setLoRaFemLnaEnabled(bool enable) override;
|
||||||
|
bool canControlLoRaFemLna() const override;
|
||||||
|
bool isLoRaFemLnaEnabled() const override;
|
||||||
uint16_t getBattMilliVolts() override;
|
uint16_t getBattMilliVolts() override;
|
||||||
bool setAdcMultiplier(float multiplier) override {
|
bool setAdcMultiplier(float multiplier) override {
|
||||||
if (multiplier == 0.0f) {
|
if (multiplier == 0.0f) {
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ class LoRaFEMControl
|
|||||||
void setRxModeEnable(void);
|
void setRxModeEnable(void);
|
||||||
void setRxModeEnableWhenMCUSleep(void);
|
void setRxModeEnableWhenMCUSleep(void);
|
||||||
void setLNAEnable(bool enabled);
|
void setLNAEnable(bool enabled);
|
||||||
bool isLnaCanControl(void) { return lna_can_control; }
|
bool isLnaCanControl(void) const { return lna_can_control; }
|
||||||
void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
|
void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
|
||||||
|
bool isLNAEnabled(void) const { return lna_enabled; }
|
||||||
LoRaFEMType getFEMType(void) const { return fem_type; }
|
LoRaFEMType getFEMType(void) const { return fem_type; }
|
||||||
private:
|
private:
|
||||||
LoRaFEMType fem_type=OTHER_FEM_TYPES;
|
LoRaFEMType fem_type=OTHER_FEM_TYPES;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <helpers/ESP32Board.h>
|
||||||
|
|
||||||
|
class TETHEliteBoard : public ESP32Board {
|
||||||
|
public:
|
||||||
|
const char* getManufacturerName() const override {
|
||||||
|
return "LilyGO T-ETH Elite";
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
[LilyGo_TETH_Elite_sx1262]
|
||||||
|
extends = esp32_base
|
||||||
|
board = esp32s3box
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
build_flags =
|
||||||
|
${esp32_base.build_flags}
|
||||||
|
-I variants/lilygo_teth_elite
|
||||||
|
-D BOARD_HAS_PSRAM
|
||||||
|
-D LILYGO_TETH_ELITE
|
||||||
|
-D LILYGO_T_ETH_ELITE_ESP32S3
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
-D P_LORA_DIO_1=8
|
||||||
|
-D P_LORA_NSS=40
|
||||||
|
-D P_LORA_RESET=46
|
||||||
|
-D P_LORA_BUSY=16
|
||||||
|
-D P_LORA_SCLK=10
|
||||||
|
-D P_LORA_MISO=9
|
||||||
|
-D P_LORA_MOSI=11
|
||||||
|
-D P_LORA_TX_LED=38
|
||||||
|
-D SX126X_DIO2_AS_RF_SWITCH=true
|
||||||
|
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
|
||||||
|
-D SX126X_CURRENT_LIMIT=140
|
||||||
|
-D USE_SX1262
|
||||||
|
-D RADIO_CLASS=CustomSX1262
|
||||||
|
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
||||||
|
-D LORA_TX_POWER=8
|
||||||
|
-D SX126X_RX_BOOSTED_GAIN=1
|
||||||
|
build_src_filter = ${esp32_base.build_src_filter}
|
||||||
|
+<../variants/lilygo_teth_elite>
|
||||||
|
lib_deps =
|
||||||
|
${esp32_base.lib_deps}
|
||||||
|
|
||||||
|
[env:LilyGo_TETH_Elite_sx1262_repeater]
|
||||||
|
extends = LilyGo_TETH_Elite_sx1262
|
||||||
|
build_flags =
|
||||||
|
${LilyGo_TETH_Elite_sx1262.build_flags}
|
||||||
|
-D ADVERT_NAME='"T-ETH Elite Repeater"'
|
||||||
|
-D ADVERT_LAT=0.0
|
||||||
|
-D ADVERT_LON=0.0
|
||||||
|
-D ADMIN_PASSWORD='"password"'
|
||||||
|
-D MAX_NEIGHBOURS=50
|
||||||
|
; -D MESH_PACKET_LOGGING=1
|
||||||
|
; -D MESH_DEBUG=1
|
||||||
|
build_src_filter = ${LilyGo_TETH_Elite_sx1262.build_src_filter}
|
||||||
|
+<../examples/simple_repeater>
|
||||||
|
lib_deps =
|
||||||
|
${LilyGo_TETH_Elite_sx1262.lib_deps}
|
||||||
|
${esp32_ota.lib_deps}
|
||||||
|
|
||||||
|
[env:LilyGo_TETH_Elite_sx1262_room_server]
|
||||||
|
extends = LilyGo_TETH_Elite_sx1262
|
||||||
|
build_flags =
|
||||||
|
${LilyGo_TETH_Elite_sx1262.build_flags}
|
||||||
|
-D ADVERT_NAME='"T-ETH Elite Room"'
|
||||||
|
-D ADVERT_LAT=0.0
|
||||||
|
-D ADVERT_LON=0.0
|
||||||
|
-D ADMIN_PASSWORD='"password"'
|
||||||
|
-D ROOM_PASSWORD='"hello"'
|
||||||
|
; -D MESH_PACKET_LOGGING=1
|
||||||
|
; -D MESH_DEBUG=1
|
||||||
|
build_src_filter = ${LilyGo_TETH_Elite_sx1262.build_src_filter}
|
||||||
|
+<../examples/simple_room_server>
|
||||||
|
lib_deps =
|
||||||
|
${LilyGo_TETH_Elite_sx1262.lib_deps}
|
||||||
|
${esp32_ota.lib_deps}
|
||||||
|
|
||||||
|
[env:LilyGo_TETH_Elite_sx1262_companion_radio_usb]
|
||||||
|
extends = LilyGo_TETH_Elite_sx1262
|
||||||
|
build_flags =
|
||||||
|
${LilyGo_TETH_Elite_sx1262.build_flags}
|
||||||
|
-D MAX_CONTACTS=350
|
||||||
|
-D MAX_GROUP_CHANNELS=40
|
||||||
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
|
; -D MESH_PACKET_LOGGING=1
|
||||||
|
; -D MESH_DEBUG=1
|
||||||
|
build_src_filter = ${LilyGo_TETH_Elite_sx1262.build_src_filter}
|
||||||
|
+<../examples/companion_radio/*.cpp>
|
||||||
|
lib_deps =
|
||||||
|
${LilyGo_TETH_Elite_sx1262.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
|
[env:LilyGo_TETH_Elite_sx1262_companion_radio_ble]
|
||||||
|
extends = LilyGo_TETH_Elite_sx1262
|
||||||
|
build_flags =
|
||||||
|
${LilyGo_TETH_Elite_sx1262.build_flags}
|
||||||
|
-D MAX_CONTACTS=350
|
||||||
|
-D MAX_GROUP_CHANNELS=40
|
||||||
|
-D BLE_PIN_CODE=123456
|
||||||
|
-D BLE_DEBUG_LOGGING=1
|
||||||
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
|
; -D MESH_PACKET_LOGGING=1
|
||||||
|
; -D MESH_DEBUG=1
|
||||||
|
build_src_filter = ${LilyGo_TETH_Elite_sx1262.build_src_filter}
|
||||||
|
+<helpers/esp32/*.cpp>
|
||||||
|
+<../examples/companion_radio/*.cpp>
|
||||||
|
lib_deps =
|
||||||
|
${LilyGo_TETH_Elite_sx1262.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
TETHEliteBoard board;
|
||||||
|
|
||||||
|
static SPIClass spi(HSPI);
|
||||||
|
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
|
||||||
|
WRAPPER_CLASS radio_driver(radio, board);
|
||||||
|
|
||||||
|
ESP32RTCClock fallback_clock;
|
||||||
|
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||||
|
SensorManager sensors;
|
||||||
|
|
||||||
|
#ifndef LORA_CR
|
||||||
|
#define LORA_CR 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool radio_init() {
|
||||||
|
fallback_clock.begin();
|
||||||
|
rtc_clock.begin(Wire);
|
||||||
|
|
||||||
|
return radio.std_init(&spi);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t radio_get_rng_seed() {
|
||||||
|
return radio.random(0x7FFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
|
||||||
|
radio.setFrequency(freq);
|
||||||
|
radio.setSpreadingFactor(sf);
|
||||||
|
radio.setBandwidth(bw);
|
||||||
|
radio.setCodingRate(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void radio_set_tx_power(int8_t dbm) {
|
||||||
|
radio.setOutputPower(dbm);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh::LocalIdentity radio_new_identity() {
|
||||||
|
RadioNoiseListener rng(radio);
|
||||||
|
return mesh::LocalIdentity(&rng);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define RADIOLIB_STATIC_ONLY 1
|
||||||
|
#include <RadioLib.h>
|
||||||
|
#include <helpers/radiolib/RadioLibWrappers.h>
|
||||||
|
#include <helpers/radiolib/CustomSX1262Wrapper.h>
|
||||||
|
#include <helpers/AutoDiscoverRTCClock.h>
|
||||||
|
#include <helpers/SensorManager.h>
|
||||||
|
#include "TETHEliteBoard.h"
|
||||||
|
|
||||||
|
extern TETHEliteBoard 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(int8_t dbm);
|
||||||
|
mesh::LocalIdentity radio_new_identity();
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
[Mesh_pocket]
|
[Mesh_pocket]
|
||||||
extends = nrf52_base
|
extends = nrf52_base
|
||||||
board = heltec_mesh_pocket
|
board = heltec_mesh_pocket
|
||||||
platform_packages = framework-arduinoadafruitnrf52
|
|
||||||
board_build.ldscript = boards/nrf52840_s140_v6.ld
|
board_build.ldscript = boards/nrf52840_s140_v6.ld
|
||||||
build_flags = ${nrf52_base.build_flags}
|
build_flags = ${nrf52_base.build_flags}
|
||||||
-I src/helpers/nrf52
|
-I src/helpers/nrf52
|
||||||
@@ -32,7 +31,6 @@ lib_deps =
|
|||||||
stevemarple/MicroNMEA @ ^2.0.6
|
stevemarple/MicroNMEA @ ^2.0.6
|
||||||
zinggjm/GxEPD2 @ 1.6.2
|
zinggjm/GxEPD2 @ 1.6.2
|
||||||
bakercp/CRC32 @ ^2.0.0
|
bakercp/CRC32 @ ^2.0.0
|
||||||
|
|
||||||
debug_tool = jlink
|
debug_tool = jlink
|
||||||
upload_protocol = nrfutil
|
upload_protocol = nrfutil
|
||||||
|
|
||||||
@@ -40,7 +38,6 @@ upload_protocol = nrfutil
|
|||||||
extends = Mesh_pocket
|
extends = Mesh_pocket
|
||||||
build_src_filter = ${Mesh_pocket.build_src_filter}
|
build_src_filter = ${Mesh_pocket.build_src_filter}
|
||||||
+<../examples/simple_repeater>
|
+<../examples/simple_repeater>
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${Mesh_pocket.build_flags}
|
${Mesh_pocket.build_flags}
|
||||||
-D ADVERT_NAME='"Heltec_Mesh_Pocket Repeater"'
|
-D ADVERT_NAME='"Heltec_Mesh_Pocket Repeater"'
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ lib_deps =
|
|||||||
adafruit/Adafruit SSD1306 @ ^2.5.13
|
adafruit/Adafruit SSD1306 @ ^2.5.13
|
||||||
adafruit/Adafruit NeoPixel @ ^1.12.3
|
adafruit/Adafruit NeoPixel @ ^1.12.3
|
||||||
|
|
||||||
[env:nibble_screen_connect_repeater]
|
[env:nibble_screen_connect_repeater_]
|
||||||
extends = nibble_screen_connect_base
|
extends = nibble_screen_connect_base
|
||||||
build_flags =
|
build_flags =
|
||||||
${nibble_screen_connect_base.build_flags}
|
${nibble_screen_connect_base.build_flags}
|
||||||
@@ -51,7 +51,7 @@ lib_deps =
|
|||||||
${nibble_screen_connect_base.lib_deps}
|
${nibble_screen_connect_base.lib_deps}
|
||||||
${esp32_ota.lib_deps}
|
${esp32_ota.lib_deps}
|
||||||
|
|
||||||
[env:nibble_screen_connect_repeater_bridge_espnow]
|
[env:nibble_screen_connect_repeater_bridge_espnow_]
|
||||||
extends = nibble_screen_connect_base
|
extends = nibble_screen_connect_base
|
||||||
build_flags =
|
build_flags =
|
||||||
${nibble_screen_connect_base.build_flags}
|
${nibble_screen_connect_base.build_flags}
|
||||||
@@ -70,7 +70,7 @@ lib_deps =
|
|||||||
${nibble_screen_connect_base.lib_deps}
|
${nibble_screen_connect_base.lib_deps}
|
||||||
${esp32_ota.lib_deps}
|
${esp32_ota.lib_deps}
|
||||||
|
|
||||||
[env:nibble_screen_connect_terminal_chat]
|
[env:nibble_screen_connect_terminal_chat_]
|
||||||
extends = nibble_screen_connect_base
|
extends = nibble_screen_connect_base
|
||||||
build_flags =
|
build_flags =
|
||||||
${nibble_screen_connect_base.build_flags}
|
${nibble_screen_connect_base.build_flags}
|
||||||
@@ -82,7 +82,7 @@ lib_deps =
|
|||||||
${nibble_screen_connect_base.lib_deps}
|
${nibble_screen_connect_base.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
[env:nibble_screen_connect_room_server]
|
[env:nibble_screen_connect_room_server_]
|
||||||
extends = nibble_screen_connect_base
|
extends = nibble_screen_connect_base
|
||||||
build_flags =
|
build_flags =
|
||||||
${nibble_screen_connect_base.build_flags}
|
${nibble_screen_connect_base.build_flags}
|
||||||
@@ -99,7 +99,7 @@ lib_deps =
|
|||||||
${nibble_screen_connect_base.lib_deps}
|
${nibble_screen_connect_base.lib_deps}
|
||||||
${esp32_ota.lib_deps}
|
${esp32_ota.lib_deps}
|
||||||
|
|
||||||
[env:nibble_screen_connect_companion_radio_usb]
|
[env:nibble_screen_connect_companion_radio_usb_]
|
||||||
extends = nibble_screen_connect_base
|
extends = nibble_screen_connect_base
|
||||||
build_flags =
|
build_flags =
|
||||||
${nibble_screen_connect_base.build_flags}
|
${nibble_screen_connect_base.build_flags}
|
||||||
@@ -116,7 +116,7 @@ lib_deps =
|
|||||||
${nibble_screen_connect_base.lib_deps}
|
${nibble_screen_connect_base.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
[env:nibble_screen_connect_companion_radio_ble]
|
[env:nibble_screen_connect_companion_radio_ble_]
|
||||||
extends = nibble_screen_connect_base
|
extends = nibble_screen_connect_base
|
||||||
build_flags =
|
build_flags =
|
||||||
${nibble_screen_connect_base.build_flags}
|
${nibble_screen_connect_base.build_flags}
|
||||||
@@ -137,7 +137,7 @@ lib_deps =
|
|||||||
${nibble_screen_connect_base.lib_deps}
|
${nibble_screen_connect_base.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
[env:nibble_screen_connect_companion_radio_wifi]
|
[env:nibble_screen_connect_companion_radio_wifi_]
|
||||||
extends = nibble_screen_connect_base
|
extends = nibble_screen_connect_base
|
||||||
build_flags =
|
build_flags =
|
||||||
${nibble_screen_connect_base.build_flags}
|
${nibble_screen_connect_base.build_flags}
|
||||||
@@ -160,7 +160,7 @@ lib_deps =
|
|||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
|
|
||||||
[env:nibble_screen_connect_kiss_modem]
|
[env:nibble_screen_connect_kiss_modem_]
|
||||||
extends = nibble_screen_connect_base
|
extends = nibble_screen_connect_base
|
||||||
build_src_filter = ${nibble_screen_connect_base.build_src_filter}
|
build_src_filter = ${nibble_screen_connect_base.build_src_filter}
|
||||||
+<../examples/kiss_modem/>
|
+<../examples/kiss_modem/>
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
[nibble_zero_connect_base]
|
||||||
|
extends = esp32_base
|
||||||
|
board = esp32-s3-zero
|
||||||
|
build_flags =
|
||||||
|
${esp32_base.build_flags}
|
||||||
|
-I variants/nibble_zero_connect
|
||||||
|
-D NIBBLE_ZERO_CONNECT
|
||||||
|
-D P_LORA_DIO_1=4
|
||||||
|
-D P_LORA_NSS=10
|
||||||
|
-D P_LORA_RESET=6
|
||||||
|
-D P_LORA_BUSY=5
|
||||||
|
-D P_LORA_SCLK=12
|
||||||
|
-D P_LORA_MISO=13
|
||||||
|
-D P_LORA_MOSI=11
|
||||||
|
-D PIN_USER_BTN=1
|
||||||
|
-D PIN_BOARD_SDA=8
|
||||||
|
-D PIN_BOARD_SCL=7
|
||||||
|
-D PIN_STATUS_LED=39
|
||||||
|
-D P_LORA_TX_LED=39
|
||||||
|
-D DISPLAY_ROTATION=0
|
||||||
|
-D SX126X_DIO2_AS_RF_SWITCH=true
|
||||||
|
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
|
||||||
|
-D SX126X_CURRENT_LIMIT=140
|
||||||
|
-D RADIO_CLASS=CustomSX1262
|
||||||
|
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
||||||
|
-D LORA_TX_POWER=22
|
||||||
|
-D SX126X_RX_BOOSTED_GAIN=1
|
||||||
|
build_src_filter = ${esp32_base.build_src_filter}
|
||||||
|
+<../variants/nibble_zero_connect>
|
||||||
|
lib_deps =
|
||||||
|
${esp32_base.lib_deps}
|
||||||
|
adafruit/Adafruit SSD1306 @ ^2.5.13
|
||||||
|
|
||||||
|
[env:nibble_zero_connect_repeater_]
|
||||||
|
extends = nibble_zero_connect_base
|
||||||
|
build_flags =
|
||||||
|
${nibble_zero_connect_base.build_flags}
|
||||||
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
|
-D ADVERT_NAME='"Nibble Repeater"'
|
||||||
|
-D ADVERT_LAT=0.0
|
||||||
|
-D ADVERT_LON=0.0
|
||||||
|
-D ADMIN_PASSWORD='"password"'
|
||||||
|
-D MAX_NEIGHBOURS=50
|
||||||
|
build_src_filter = ${nibble_zero_connect_base.build_src_filter}
|
||||||
|
+<helpers/ui/SSD1306Display.cpp>
|
||||||
|
+<../examples/simple_repeater>
|
||||||
|
lib_deps =
|
||||||
|
${nibble_zero_connect_base.lib_deps}
|
||||||
|
${esp32_ota.lib_deps}
|
||||||
|
|
||||||
|
[env:nibble_zero_connect_repeater_bridge_espnow_]
|
||||||
|
extends = nibble_zero_connect_base
|
||||||
|
build_flags =
|
||||||
|
${nibble_zero_connect_base.build_flags}
|
||||||
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
|
-D ADVERT_NAME='"ESPNow Bridge"'
|
||||||
|
-D ADVERT_LAT=0.0
|
||||||
|
-D ADVERT_LON=0.0
|
||||||
|
-D ADMIN_PASSWORD='"password"'
|
||||||
|
-D MAX_NEIGHBOURS=50
|
||||||
|
-D WITH_ESPNOW_BRIDGE=1
|
||||||
|
build_src_filter = ${nibble_zero_connect_base.build_src_filter}
|
||||||
|
+<helpers/bridges/ESPNowBridge.cpp>
|
||||||
|
+<helpers/ui/SSD1306Display.cpp>
|
||||||
|
+<../examples/simple_repeater>
|
||||||
|
lib_deps =
|
||||||
|
${nibble_zero_connect_base.lib_deps}
|
||||||
|
${esp32_ota.lib_deps}
|
||||||
|
|
||||||
|
[env:nibble_zero_connect_terminal_chat_]
|
||||||
|
extends = nibble_zero_connect_base
|
||||||
|
build_flags =
|
||||||
|
${nibble_zero_connect_base.build_flags}
|
||||||
|
-D MAX_CONTACTS=300
|
||||||
|
-D MAX_GROUP_CHANNELS=1
|
||||||
|
build_src_filter = ${nibble_zero_connect_base.build_src_filter}
|
||||||
|
+<../examples/simple_secure_chat/main.cpp>
|
||||||
|
lib_deps =
|
||||||
|
${nibble_zero_connect_base.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
|
[env:nibble_zero_connect_room_server_]
|
||||||
|
extends = nibble_zero_connect_base
|
||||||
|
build_flags =
|
||||||
|
${nibble_zero_connect_base.build_flags}
|
||||||
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
|
-D ADVERT_NAME='"Nibble Room"'
|
||||||
|
-D ADVERT_LAT=0.0
|
||||||
|
-D ADVERT_LON=0.0
|
||||||
|
-D ADMIN_PASSWORD='"password"'
|
||||||
|
-D ROOM_PASSWORD='"hello"'
|
||||||
|
build_src_filter = ${nibble_zero_connect_base.build_src_filter}
|
||||||
|
+<helpers/ui/SSD1306Display.cpp>
|
||||||
|
+<../examples/simple_room_server>
|
||||||
|
lib_deps =
|
||||||
|
${nibble_zero_connect_base.lib_deps}
|
||||||
|
${esp32_ota.lib_deps}
|
||||||
|
|
||||||
|
[env:nibble_zero_connect_companion_radio_usb_]
|
||||||
|
extends = nibble_zero_connect_base
|
||||||
|
build_flags =
|
||||||
|
${nibble_zero_connect_base.build_flags}
|
||||||
|
-I examples/companion_radio/ui-new
|
||||||
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
|
-D MAX_CONTACTS=300
|
||||||
|
-D MAX_GROUP_CHANNELS=8
|
||||||
|
build_src_filter = ${nibble_zero_connect_base.build_src_filter}
|
||||||
|
+<helpers/ui/SSD1306Display.cpp>
|
||||||
|
+<helpers/ui/MomentaryButton.cpp>
|
||||||
|
+<../examples/companion_radio/*.cpp>
|
||||||
|
+<../examples/companion_radio/ui-new/*.cpp>
|
||||||
|
lib_deps =
|
||||||
|
${nibble_zero_connect_base.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
|
[env:nibble_zero_connect_companion_radio_ble_]
|
||||||
|
extends = nibble_zero_connect_base
|
||||||
|
build_flags =
|
||||||
|
${nibble_zero_connect_base.build_flags}
|
||||||
|
-I examples/companion_radio/ui-new
|
||||||
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
|
-D MAX_CONTACTS=300
|
||||||
|
-D MAX_GROUP_CHANNELS=8
|
||||||
|
-D BLE_PIN_CODE=123456
|
||||||
|
-D BLE_DEBUG_LOGGING=1
|
||||||
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
|
build_src_filter = ${nibble_zero_connect_base.build_src_filter}
|
||||||
|
+<helpers/esp32/*.cpp>
|
||||||
|
+<helpers/ui/SSD1306Display.cpp>
|
||||||
|
+<helpers/ui/MomentaryButton.cpp>
|
||||||
|
+<../examples/companion_radio/*.cpp>
|
||||||
|
+<../examples/companion_radio/ui-new/*.cpp>
|
||||||
|
lib_deps =
|
||||||
|
${nibble_zero_connect_base.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
|
[env:nibble_zero_connect_companion_radio_wifi_]
|
||||||
|
extends = nibble_zero_connect_base
|
||||||
|
build_flags =
|
||||||
|
${nibble_zero_connect_base.build_flags}
|
||||||
|
-I examples/companion_radio/ui-new
|
||||||
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
|
-D MAX_CONTACTS=300
|
||||||
|
-D MAX_GROUP_CHANNELS=8
|
||||||
|
-D WIFI_DEBUG_LOGGING=1
|
||||||
|
-D WIFI_SSID='"myssid"'
|
||||||
|
-D WIFI_PWD='"mypwd"'
|
||||||
|
build_src_filter = ${nibble_zero_connect_base.build_src_filter}
|
||||||
|
+<helpers/ui/SSD1306Display.cpp>
|
||||||
|
+<helpers/ui/MomentaryButton.cpp>
|
||||||
|
+<helpers/esp32/*.cpp>
|
||||||
|
+<../examples/companion_radio/*.cpp>
|
||||||
|
+<../examples/companion_radio/ui-new/*.cpp>
|
||||||
|
lib_deps =
|
||||||
|
${nibble_zero_connect_base.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
|
ESP32Board board;
|
||||||
|
|
||||||
|
static SPIClass spi;
|
||||||
|
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
|
||||||
|
WRAPPER_CLASS radio_driver(radio, board);
|
||||||
|
|
||||||
|
ESP32RTCClock fallback_clock;
|
||||||
|
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||||
|
SensorManager sensors;
|
||||||
|
|
||||||
|
#ifdef DISPLAY_CLASS
|
||||||
|
DISPLAY_CLASS display;
|
||||||
|
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LORA_CR
|
||||||
|
#define LORA_CR 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool radio_init() {
|
||||||
|
fallback_clock.begin();
|
||||||
|
rtc_clock.begin(Wire);
|
||||||
|
|
||||||
|
return radio.std_init(&spi);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh::LocalIdentity radio_new_identity() {
|
||||||
|
RadioNoiseListener rng(radio);
|
||||||
|
return mesh::LocalIdentity(&rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define RADIOLIB_STATIC_ONLY 1
|
||||||
|
#include <RadioLib.h>
|
||||||
|
#include <helpers/radiolib/RadioLibWrappers.h>
|
||||||
|
#include <helpers/ESP32Board.h>
|
||||||
|
#include <helpers/radiolib/CustomSX1262Wrapper.h>
|
||||||
|
#include <helpers/AutoDiscoverRTCClock.h>
|
||||||
|
#include <helpers/SensorManager.h>
|
||||||
|
#ifdef DISPLAY_CLASS
|
||||||
|
#include <helpers/ui/SSD1306Display.h>
|
||||||
|
#include <helpers/ui/MomentaryButton.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern ESP32Board board;
|
||||||
|
extern WRAPPER_CLASS radio_driver;
|
||||||
|
extern AutoDiscoverRTCClock rtc_clock;
|
||||||
|
extern SensorManager sensors;
|
||||||
|
|
||||||
|
#ifdef DISPLAY_CLASS
|
||||||
|
extern DISPLAY_CLASS display;
|
||||||
|
extern MomentaryButton user_btn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool radio_init();
|
||||||
|
mesh::LocalIdentity radio_new_identity();
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
[Xiao_C6]
|
[Xiao_C6]
|
||||||
extends = esp32c6_base
|
extends = esp32c6_base
|
||||||
board = esp32-c6-devkitm-1
|
board = esp32-c6-devkitm-1
|
||||||
|
board_build.flash_mode = dio
|
||||||
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
|
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32c6_base.build_flags}
|
${esp32c6_base.build_flags}
|
||||||
|
|||||||
Reference in New Issue
Block a user