mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-04 03:18:10 +10:00
Compare commits
229
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97fd5cf2ab | ||
|
|
d13a095516 | ||
|
|
4dc7d92cf1 | ||
|
|
e7dbbeb606 | ||
|
|
3e892fc391 | ||
|
|
dfec37dfd0 | ||
|
|
b82ab34f85 | ||
|
|
18a2cfeda4 | ||
|
|
082aa07e7f | ||
|
|
a703ab4418 | ||
|
|
185ceac9df | ||
|
|
7c9cada50e | ||
|
|
a5ba3dd445 | ||
|
|
63838a1632 | ||
|
|
30d7f188e2 | ||
|
|
47a47f1e69 | ||
|
|
daac79f314 | ||
|
|
1864216e78 | ||
|
|
71c0cf9b9a | ||
|
|
ef87ddb798 | ||
|
|
711c748b44 | ||
|
|
6eff09a260 | ||
|
|
c5fe878a6f | ||
|
|
39948c76de | ||
|
|
10f14d27b7 | ||
|
|
5e9d722b7d | ||
|
|
b324c04097 | ||
|
|
84a9d95b1f | ||
|
|
cdd499f147 | ||
|
|
c45a85547e | ||
|
|
8815746006 | ||
|
|
32a1e8ef0d | ||
|
|
0dff4538f3 | ||
|
|
6507683909 | ||
|
|
c71e32970c | ||
|
|
fcf21da843 | ||
|
|
ab464fe038 | ||
|
|
fd546af2a5 | ||
|
|
acfbe202b6 | ||
|
|
29fb283daf | ||
|
|
51ef9b7fbe | ||
|
|
025d2264a2 | ||
|
|
b2284b2097 | ||
|
|
5f8267c956 | ||
|
|
cf783a5bae | ||
|
|
32e5ced814 | ||
|
|
605fadabcf | ||
|
|
e91ace7329 | ||
|
|
c87cd136d4 | ||
|
|
0d7d59609a | ||
|
|
75ed0e5906 | ||
|
|
8e3b500307 | ||
|
|
d6f77bf07e | ||
|
|
65e8209d51 | ||
|
|
aae5247caa | ||
|
|
2fedb6b774 | ||
|
|
02d18d4831 | ||
|
|
b70c2d088d | ||
|
|
b3c396683e | ||
|
|
f08874dd37 | ||
|
|
648054da9b | ||
|
|
70bf7c490c | ||
|
|
adbed5de95 | ||
|
|
fe989f0bff | ||
|
|
679e346bcb | ||
|
|
832439b336 | ||
|
|
71c2af04ec | ||
|
|
0f4261d02f | ||
|
|
23466d8eee | ||
|
|
8edbba2180 | ||
|
|
5417671332 | ||
|
|
35d7e11678 | ||
|
|
7a63ba827b | ||
|
|
71c163a8ee | ||
|
|
5d8e661807 | ||
|
|
24244e8474 | ||
|
|
fb4f9bdc40 | ||
|
|
668c46e0cf | ||
|
|
abf8fdb661 | ||
|
|
a28a04b7a0 | ||
|
|
cd9671650b | ||
|
|
00bc762bf1 | ||
|
|
9a065bce03 | ||
|
|
3b2b0bdc97 | ||
|
|
53cd6bdf15 | ||
|
|
edc97c1c07 | ||
|
|
6a24ef2263 | ||
|
|
50ba523fb4 | ||
|
|
a33325f90f | ||
|
|
a173b7159a | ||
|
|
91295d3772 | ||
|
|
9c1c04a8db | ||
|
|
51d0d0d779 | ||
|
|
9cdf627ae3 | ||
|
|
4b9c482384 | ||
|
|
b1ba807ec9 | ||
|
|
c844f153e1 | ||
|
|
4a2b02347f | ||
|
|
e8a05d1874 | ||
|
|
08c4e3fbd6 | ||
|
|
1c5292ac86 | ||
|
|
aa553ea5d8 | ||
|
|
a00bd59e27 | ||
|
|
f02c6c49ee | ||
|
|
e54e37a600 | ||
|
|
b95103cab0 | ||
|
|
9b43e49116 | ||
|
|
457538c8f6 | ||
|
|
da48f0704b | ||
|
|
cf8d953bba | ||
|
|
5f2b859e38 | ||
|
|
3187b5abda | ||
|
|
ce16b50d5f | ||
|
|
4295720770 | ||
|
|
4392df0676 | ||
|
|
4ec3b025f0 | ||
|
|
f4704181e9 | ||
|
|
0e04bea39e | ||
|
|
b54044fd00 | ||
|
|
08c69c09c8 | ||
|
|
681ea420c1 | ||
|
|
48ea54748f | ||
|
|
4b7627595a | ||
|
|
6299e5483b | ||
|
|
6118a966a6 | ||
|
|
1fac9ee1f2 | ||
|
|
1e06b2d51e | ||
|
|
f3a6ed9d61 | ||
|
|
f71cbb6f6e | ||
|
|
23ea22c741 | ||
|
|
8be65bb0ab | ||
|
|
57e2e75d24 | ||
|
|
29cd7568f5 | ||
|
|
581076a5a1 | ||
|
|
27401bb9b8 | ||
|
|
10837ce549 | ||
|
|
1dcd411d00 | ||
|
|
0533fd9227 | ||
|
|
5ce7ffc888 | ||
|
|
9e914de995 | ||
|
|
0cc653263e | ||
|
|
d2d2f278cf | ||
|
|
eb34a95ab7 | ||
|
|
eb1f6c0de6 | ||
|
|
8de79e8fb6 | ||
|
|
fe00f0c369 | ||
|
|
f9ee8583b0 | ||
|
|
a4d5f8c717 | ||
|
|
35c50f074b | ||
|
|
dcfa226509 | ||
|
|
a9fde30a58 | ||
|
|
7ceb52103e | ||
|
|
8da5d37888 | ||
|
|
95cc328b5c | ||
|
|
990c0119a7 | ||
|
|
144afee29e | ||
|
|
9665c08b59 | ||
|
|
20ee6a509d | ||
|
|
70d44b8838 | ||
|
|
b260c8b058 | ||
|
|
5991b59ba3 | ||
|
|
bc1fed0fb4 | ||
|
|
b23c364fc0 | ||
|
|
28b428c5a0 | ||
|
|
5bfc58ed64 | ||
|
|
e9a34fca7b | ||
|
|
6ce9734ddd | ||
|
|
d42797ffeb | ||
|
|
b5ebfa9cc3 | ||
|
|
79eff42c3c | ||
|
|
7022807fa3 | ||
|
|
50a301899e | ||
|
|
351db5f6ef | ||
|
|
09fe616ac5 | ||
|
|
2d7ff39ecc | ||
|
|
6e856efd0e | ||
|
|
c3c899bc85 | ||
|
|
916f3cac41 | ||
|
|
9b5f358823 | ||
|
|
22119c272d | ||
|
|
8d4c526d16 | ||
|
|
83aebb7a00 | ||
|
|
33cd5ce6c1 | ||
|
|
f22c2e768e | ||
|
|
3d7dea0606 | ||
|
|
263a421c4a | ||
|
|
401b92bdbb | ||
|
|
6a696af8f6 | ||
|
|
037d6c253b | ||
|
|
b6de79b21a | ||
|
|
52cf530356 | ||
|
|
861ded37db | ||
|
|
7a67388a97 | ||
|
|
4f60fad3f6 | ||
|
|
67efd8172a | ||
|
|
60fdf9fcb2 | ||
|
|
a606e9b7b5 | ||
|
|
65197a8e48 | ||
|
|
43f769ebac | ||
|
|
dff6eeb90e | ||
|
|
61ebdb3367 | ||
|
|
cd95d0865f | ||
|
|
b68a026627 | ||
|
|
68ccebafbf | ||
|
|
3737252d39 | ||
|
|
888a8d05c4 | ||
|
|
f25f902c20 | ||
|
|
a6ea5496b4 | ||
|
|
222424a80c | ||
|
|
74f31d7d68 | ||
|
|
5c59c8d701 | ||
|
|
30a87e3145 | ||
|
|
87f7a60f71 | ||
|
|
f7d8885257 | ||
|
|
77410dc3c3 | ||
|
|
d1acf02ee8 | ||
|
|
de0954f307 | ||
|
|
7da1e5c3e8 | ||
|
|
3c11e87197 | ||
|
|
b004706eff | ||
|
|
2247e71a52 | ||
|
|
30b6cca366 | ||
|
|
4dd140a887 | ||
|
|
87c555bde3 | ||
|
|
c4951b1236 | ||
|
|
0249eb1307 | ||
|
|
803858ab0a | ||
|
|
da2279c295 | ||
|
|
13e635b74e |
@@ -0,0 +1,27 @@
|
||||
name: Feature Request
|
||||
description: Request a new feature
|
||||
title: "[Feature Request]: "
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for your request this will not gurantee that we will implement it, but it will be reviewed.
|
||||
- type: dropdown
|
||||
id: soc
|
||||
attributes:
|
||||
label: Platform
|
||||
description: What device platform will support your feature?
|
||||
multiple: true
|
||||
options:
|
||||
- NRF52
|
||||
- ESP32
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: body
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please provide details about your enhancement.
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,41 @@
|
||||
name: 'Setup Build Base Composite Action'
|
||||
description: 'Base build actions for Meshtastic Platform IO steps'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Install cppcheck
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get install -y cppcheck
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
pip install -U meshtastic --pre
|
||||
|
||||
- name: Upgrade platformio
|
||||
shell: bash
|
||||
run: |
|
||||
pio upgrade
|
||||
@@ -0,0 +1,54 @@
|
||||
name: Build ESP32
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
board:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-esp32:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
run: |
|
||||
tar -xf build.tar -C data/static
|
||||
rm build.tar
|
||||
|
||||
- name: Build ESP32
|
||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||
|
||||
- name: Pull OTA Firmware
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/firmware-ota"
|
||||
file: "firmware.bin"
|
||||
target: "release/bleota.bin"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
shell: bash
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.bin
|
||||
release/*.elf
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Build NRF52
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
board:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-nrf52:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Build NRF52
|
||||
run: bin/build-nrf52.sh ${{ inputs.board }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.uf2
|
||||
release/*.elf
|
||||
release/*.zip
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Build RPI2040
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
board:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-rpi2040:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Build Raspberry Pi 2040
|
||||
run: ./bin/build-rpi2040.sh ${{ inputs.board }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.uf2
|
||||
release/*.elf
|
||||
@@ -23,61 +23,22 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- board: rak11200
|
||||
- board: tlora-v2
|
||||
- board: tlora-v1
|
||||
- board: tlora_v1_3
|
||||
- board: tlora-v2-1-1.6
|
||||
- board: tbeam
|
||||
- board: heltec-v1
|
||||
- board: heltec-v2.0
|
||||
- board: heltec-v2.1
|
||||
- board: tbeam0.7
|
||||
- board: meshtastic-diy-v1
|
||||
- board: meshtastic-dr-dev
|
||||
- board: rak4631
|
||||
- board: rak4631_eink
|
||||
- board: t-echo
|
||||
- board: nano-g1
|
||||
- board: station-g1
|
||||
- board: m5stack-core
|
||||
- board: m5stack-coreink
|
||||
- board: tbeam-s3-core
|
||||
- board: feather_diy
|
||||
# - board: pico
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Install cppcheck
|
||||
run: |
|
||||
sudo apt-get install -y cppcheck
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools and install platformio
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Check ${{ matrix.board }}
|
||||
run: bin/check-all.sh ${{ matrix.board }}
|
||||
@@ -96,6 +57,8 @@ jobs:
|
||||
- board: heltec-v1
|
||||
- board: heltec-v2.0
|
||||
- board: heltec-v2.1
|
||||
- board: heltec-v3
|
||||
- board: heltec-wsl-v3
|
||||
- board: tbeam0.7
|
||||
- board: meshtastic-diy-v1
|
||||
- board: meshtastic-dr-dev
|
||||
@@ -104,73 +67,9 @@ jobs:
|
||||
- board: m5stack-core
|
||||
- board: m5stack-coreink
|
||||
- board: tbeam-s3-core
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
run: |
|
||||
tar -xf build.tar -C data/static
|
||||
rm build.tar
|
||||
|
||||
- name: Build ESP32
|
||||
run: bin/build-esp32.sh ${{ matrix.board }}
|
||||
|
||||
- name: Pull OTA Firmware
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/firmware-ota"
|
||||
file: "firmware.bin"
|
||||
target: "release/bleota.bin"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.bin
|
||||
release/*.elf
|
||||
retention-days: 30
|
||||
uses: ./.github/workflows/build_esp32.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
|
||||
build-nrf52:
|
||||
strategy:
|
||||
@@ -183,53 +82,9 @@ jobs:
|
||||
- board: t-echo
|
||||
- board: pca10059_diy_eink
|
||||
- board: feather_diy
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Build NRF52
|
||||
run: bin/build-nrf52.sh ${{ matrix.board }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.uf2
|
||||
release/*.elf
|
||||
release/*.zip
|
||||
retention-days: 30
|
||||
uses: ./.github/workflows/build_nrf52.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
|
||||
build-rpi2040:
|
||||
strategy:
|
||||
@@ -238,84 +93,17 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- board: pico
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Build Raspberry Pi 2040
|
||||
run: ./bin/build-rpi2040.sh ${{ matrix.board }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.uf2
|
||||
release/*.elf
|
||||
retention-days: 30
|
||||
uses: ./.github/workflows/build_rpi2040.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
|
||||
build-native:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
pip install -U meshtastic --pre
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
# We now run integration test before other build steps (to quickly see runtime failures)
|
||||
- name: Build for native
|
||||
@@ -339,11 +127,29 @@ jobs:
|
||||
with:
|
||||
name: firmware-native-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/meshtasticd_linux_amd64
|
||||
release/device-*.sh
|
||||
release/device-*.bat
|
||||
retention-days: 30
|
||||
|
||||
- name: Docker login
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: meshtastic
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Docker setup
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Docker build and push
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: meshtastic/device-simulator:latest
|
||||
|
||||
after-checks:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check]
|
||||
@@ -373,7 +179,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Move files up
|
||||
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
|
||||
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -383,7 +189,6 @@ jobs:
|
||||
./*.bin
|
||||
./*.uf2
|
||||
./firmware-*-ota.zip
|
||||
./meshtasticd_linux_amd64
|
||||
./device-*.sh
|
||||
./device-*.bat
|
||||
retention-days: 90
|
||||
@@ -403,7 +208,7 @@ jobs:
|
||||
chmod +x ./output/device-update.sh
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
|
||||
run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -452,7 +257,7 @@ jobs:
|
||||
chmod +x ./output/device-update.sh
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
|
||||
run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
@@ -460,7 +265,7 @@ jobs:
|
||||
path: ./elfs
|
||||
|
||||
- name: Zip Elfs
|
||||
run: zip -j -r ./debug-elfs-${{ steps.version.outputs.version }}.zip ./elfs
|
||||
run: zip -j -9 -r ./debug-elfs-${{ steps.version.outputs.version }}.zip ./elfs
|
||||
|
||||
# For diagnostics
|
||||
- name: Show artifacts
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
name: Flawfinder Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, develop]
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "version.properties"
|
||||
|
||||
jobs:
|
||||
flawfinder:
|
||||
runs-on: ubuntu-latest
|
||||
name: Flawfinder
|
||||
|
||||
steps:
|
||||
# step 1
|
||||
- name: clone application source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# step 2
|
||||
- name: flawfinder_scan
|
||||
uses: david-a-wheeler/flawfinder@2.0.19
|
||||
with:
|
||||
arguments: '--sarif ./'
|
||||
output: 'flawfinder_report.sarif'
|
||||
|
||||
# step 3
|
||||
- name: save report as pipeline artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flawfinder_report.sarif
|
||||
path: flawfinder_report.sarif
|
||||
|
||||
# step 4
|
||||
- name: publish code scanning alerts
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: flawfinder_report.sarif
|
||||
category: flawfinder
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
name: Semgrep Full Scan
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
branches:
|
||||
- master
|
||||
schedule:
|
||||
- cron: '0 1 * * 6'
|
||||
|
||||
jobs:
|
||||
|
||||
semgrep-full:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: returntocorp/semgrep
|
||||
|
||||
steps:
|
||||
|
||||
# step 1
|
||||
- name: clone application source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# step 2
|
||||
- name: full scan
|
||||
run: |
|
||||
semgrep \
|
||||
--sarif --output report.sarif \
|
||||
--metrics=off \
|
||||
--config="p/default"
|
||||
|
||||
# step 3
|
||||
- name: save report as pipeline artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: report.sarif
|
||||
path: report.sarif
|
||||
|
||||
# step 4
|
||||
- name: publish code scanning alerts
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: report.sarif
|
||||
category: semgrep
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Semgrep Differential Scan
|
||||
on:
|
||||
pull_request
|
||||
|
||||
jobs:
|
||||
|
||||
semgrep-diff:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: returntocorp/semgrep
|
||||
|
||||
steps:
|
||||
|
||||
# step 1
|
||||
- name: clone application source code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# step 2
|
||||
- name: differential scan
|
||||
run: |
|
||||
semgrep scan \
|
||||
--error \
|
||||
--metrics=off \
|
||||
--baseline-commit ${{ github.event.pull_request.base.sha }} \
|
||||
--config="p/default"
|
||||
@@ -1,4 +1,3 @@
|
||||
[submodule "protobufs"]
|
||||
path = protobufs
|
||||
url = https://github.com/meshtastic/protobufs.git
|
||||
branch = develop
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
.github/workflows/main_matrix.yml
|
||||
src/mesh/compression/unishox2.c
|
||||
+38
-12
@@ -1,15 +1,41 @@
|
||||
FROM debian:bullseye-slim AS builder
|
||||
RUN apt-get update
|
||||
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install wget python3 g++ zip python3-venv git vim
|
||||
RUN wget https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py -O get-platformio.py; chmod +x get-platformio.py
|
||||
RUN python3 get-platformio.py
|
||||
RUN git clone https://github.com/meshtastic/firmware --recurse-submodules
|
||||
RUN cd firmware
|
||||
RUN chmod +x ./firmware/bin/build-native.sh
|
||||
RUN . ~/.platformio/penv/bin/activate; cd firmware; sh ./bin/build-native.sh
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=Etc/UTC
|
||||
|
||||
# http://bugs.python.org/issue19846
|
||||
# > At the moment, setting "LANG=C" on a Linux system *fundamentally breaks Python 3*, and that's not OK.
|
||||
ENV LANG C.UTF-8
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
# Install build deps
|
||||
USER root
|
||||
RUN apt-get update && \
|
||||
apt-get -y install wget python3 g++ zip python3-venv git vim ca-certificates
|
||||
|
||||
# create a non-priveleged user & group
|
||||
RUN groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh
|
||||
|
||||
USER mesh
|
||||
RUN wget https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py -qO /tmp/get-platformio.py && \
|
||||
chmod +x /tmp/get-platformio.py && \
|
||||
python3 /tmp/get-platformio.py && \
|
||||
git clone https://github.com/meshtastic/firmware --recurse-submodules /tmp/firmware && \
|
||||
cd /tmp/firmware && \
|
||||
chmod +x /tmp/firmware/bin/build-native.sh && \
|
||||
source ~/.platformio/penv/bin/activate && \
|
||||
./bin/build-native.sh
|
||||
|
||||
FROM frolvlad/alpine-glibc
|
||||
WORKDIR /root/
|
||||
COPY --from=builder /firmware/release/meshtasticd_linux_amd64 ./
|
||||
RUN apk --update add --no-cache g++
|
||||
CMD sh -cx "./meshtasticd_linux_amd64 --hwid '$RANDOM'"
|
||||
|
||||
RUN apk --update add --no-cache g++ shadow && \
|
||||
groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh
|
||||
|
||||
COPY --from=builder /tmp/firmware/release/meshtasticd_linux_amd64 /home/mesh/
|
||||
|
||||
USER mesh
|
||||
WORKDIR /home/mesh
|
||||
CMD sh -cx "./meshtasticd_linux_amd64 --hwid '$RANDOM'"
|
||||
|
||||
HEALTHCHECK NONE
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
This repository contains the device firmware for the Meshtastic project.
|
||||
|
||||
**[Building Instructions](https://meshtastic.org/docs/developers/Firmware/build)**
|
||||
**[Building Instructions](https://meshtastic.org/docs/development/firmware/build)**
|
||||
**[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)**
|
||||
|
||||
## Stats
|
||||
|
||||
@@ -31,7 +31,7 @@ lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#657509856ce97e9dddeffb89a559f544faefd5cd
|
||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#657509856ce97e9dddeffb89a559f544faefd5cd
|
||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||
[portduino_base]
|
||||
platform = https://github.com/meshtastic/platform-native.git#096b3c3e9c5c8e19d4c3b6cd803fffef2a9be4c5
|
||||
framework = arduino
|
||||
build_src_filter =
|
||||
${env.build_src_filter}
|
||||
-<platform/esp32/>
|
||||
@@ -16,5 +18,4 @@ lib_deps =
|
||||
${env.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
rweather/Crypto@^0.4.0
|
||||
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
|
||||
build_flags = ${arduino_base.build_flags} -Isrc/platform/portduino
|
||||
|
||||
+4
-3
@@ -10,9 +10,6 @@ OUTDIR=release/
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
|
||||
# Make sure our submodules are current
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio pkg update
|
||||
|
||||
@@ -32,6 +29,10 @@ echo "Copying ESP32 bin file"
|
||||
SRCBIN=.pio/build/$1/firmware.factory.bin
|
||||
cp $SRCBIN $OUTDIR/$basename.bin
|
||||
|
||||
echo "Copying ESP32 update bin file"
|
||||
SRCBIN=.pio/build/$1/firmware.bin
|
||||
cp $SRCBIN $OUTDIR/$basename-update.bin
|
||||
|
||||
echo "Building Filesystem for ESP32 targets"
|
||||
pio run --environment tbeam -t buildfs
|
||||
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
|
||||
|
||||
@@ -12,9 +12,6 @@ rm -f $OUTDIR/firmware*
|
||||
mkdir -p $OUTDIR/
|
||||
rm -r $OUTDIR/* || true
|
||||
|
||||
# Make sure our submodules are current
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio pkg update
|
||||
|
||||
|
||||
@@ -10,9 +10,6 @@ OUTDIR=release/
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
|
||||
# Make sure our submodules are current
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio pkg update
|
||||
|
||||
|
||||
@@ -10,9 +10,6 @@ OUTDIR=release/
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
|
||||
# Make sure our submodules are current
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio pkg update
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ IF "__%FILENAME%__" == "____" (
|
||||
echo "Missing FILENAME"
|
||||
goto HELP
|
||||
)
|
||||
IF EXIST %FILENAME% (
|
||||
IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
|
||||
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
|
||||
%PYTHON% -m esptool --baud 115200 erase_flash
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||
@@ -37,6 +37,9 @@ IF EXIST %FILENAME% (
|
||||
) else (
|
||||
echo "Invalid file: %FILENAME%"
|
||||
goto HELP
|
||||
) else (
|
||||
echo "Invalid file: %FILENAME%"
|
||||
goto HELP
|
||||
)
|
||||
|
||||
:EOF
|
||||
|
||||
@@ -14,6 +14,7 @@ Flash image file to device, but first erasing and writing system information"
|
||||
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
|
||||
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
|
||||
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -44,7 +45,7 @@ shift "$((OPTIND-1))"
|
||||
shift
|
||||
}
|
||||
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
if [ -f "${FILENAME}" ] && [[ "${FILENAME}" != *"update"* ]]; then
|
||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||
"$PYTHON" -m esptool erase_flash
|
||||
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
|
||||
@@ -52,8 +53,8 @@ if [ -f "${FILENAME}" ]; then
|
||||
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
|
||||
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -10,7 +10,7 @@ echo.
|
||||
echo -h Display this help and exit
|
||||
echo -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
|
||||
echo -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: %PYTHON%)
|
||||
echo -f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
echo -f FILENAME The *update.bin file to flash. Custom to your device type.
|
||||
goto EOF
|
||||
|
||||
:GETOPTS
|
||||
@@ -26,9 +26,12 @@ IF "__%FILENAME%__" == "____" (
|
||||
echo "Missing FILENAME"
|
||||
goto HELP
|
||||
)
|
||||
IF EXIST %FILENAME% (
|
||||
IF EXIST %FILENAME% IF NOT x%FILENAME:update=%==x%FILENAME% (
|
||||
echo Trying to flash update %FILENAME%
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
|
||||
) else (
|
||||
echo "Invalid file: %FILENAME%"
|
||||
goto HELP
|
||||
) else (
|
||||
echo "Invalid file: %FILENAME%"
|
||||
goto HELP
|
||||
|
||||
@@ -11,7 +11,8 @@ Flash image file to device, leave existing system intact."
|
||||
-h Display this help and exit
|
||||
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
|
||||
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
|
||||
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||
-f FILENAME The *update.bin file to flash. Custom to your device type.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -42,12 +43,12 @@ shift "$((OPTIND-1))"
|
||||
shift
|
||||
}
|
||||
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
echo "Trying to flash update ${FILENAME}."
|
||||
$PYTHON -m esptool --baud 115200 write_flash 0x00 ${FILENAME}
|
||||
if [ -f "${FILENAME}" ] && [[ $FILENAME == *"update"* ]]; then
|
||||
printf "Trying to flash update ${FILENAME}"
|
||||
$PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME}
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ services:
|
||||
build: .
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 80
|
||||
replicas: 4
|
||||
networks:
|
||||
- mesh
|
||||
|
||||
|
||||
+17
-7
@@ -37,12 +37,24 @@ extra_scripts = bin/platformio-custom.py
|
||||
; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile
|
||||
; of code is a heap corruption bug!
|
||||
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
|
||||
; The Radiolib stuff will speed up building considerably. Exclud all the stuff we dont need.
|
||||
build_flags = -Wno-missing-field-initializers
|
||||
-Wno-format
|
||||
-Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
|
||||
-DUSE_THREAD_NAMES
|
||||
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
-DPB_ENABLE_MALLOC=1
|
||||
-DRADIOLIB_EXCLUDE_CC1101
|
||||
-DRADIOLIB_EXCLUDE_NRF24
|
||||
-DRADIOLIB_EXCLUDE_RF69
|
||||
-DRADIOLIB_EXCLUDE_SX1231
|
||||
-DRADIOLIB_EXCLUDE_SI443X
|
||||
-DRADIOLIB_EXCLUDE_RFM2X
|
||||
-DRADIOLIB_EXCLUDE_AFSK
|
||||
-DRADIOLIB_EXCLUDE_HELLSCHREIBER
|
||||
-DRADIOLIB_EXCLUDE_MORSE
|
||||
-DRADIOLIB_EXCLUDE_RTTY
|
||||
-DRADIOLIB_EXCLUDE_SSTV
|
||||
|
||||
monitor_speed = 115200
|
||||
|
||||
@@ -50,10 +62,11 @@ lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#53580644255b48ebb7a737343c6b4e71c7e11cf2 ; ESP8266_SSD1306
|
||||
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
|
||||
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#2f0d0528d737000043e949f4c3bdfb623cf0b902
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
|
||||
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
nanopb/Nanopb@^0.4.6
|
||||
erriez/ErriezCRC32@^1.0.1
|
||||
jgromes/RadioLib@^5.5.0
|
||||
|
||||
; Used for the code analysis in PIO Home / Inspect
|
||||
check_tool = cppcheck
|
||||
@@ -61,19 +74,17 @@ check_skip_packages = yes
|
||||
check_flags =
|
||||
-DAPP_VERSION=1.0.0
|
||||
--suppressions-list=suppressions.txt
|
||||
--inline-suppr
|
||||
|
||||
; Common settings for conventional (non Portduino) Arduino targets
|
||||
[arduino_base]
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
; Portduino is using meshtastic fork for now
|
||||
jgromes/RadioLib@5.4.1
|
||||
mprograms/QMC5883LCompass@^1.1.1
|
||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
|
||||
|
||||
build_flags = ${env.build_flags} -Os
|
||||
-DRADIOLIB_SPI_PARANOID=0
|
||||
# -DRADIOLIB_GODMODE
|
||||
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
|
||||
build_src_filter = ${env.build_src_filter} -<platform/portduino/>
|
||||
|
||||
; Common libs for communicating over TCP/IP networks such as MQTT
|
||||
@@ -81,7 +92,6 @@ build_src_filter = ${env.build_src_filter} -<platform/portduino/>
|
||||
lib_deps =
|
||||
knolleary/PubSubClient@^2.8
|
||||
arduino-libraries/NTPClient@^3.1.0
|
||||
meshtastic/json11@^1.0.2
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
; (not included in native / portduino)
|
||||
|
||||
+1
-1
Submodule protobufs updated: c82c15aac7...afa4605699
@@ -1,6 +1,18 @@
|
||||
#include "configuration.h"
|
||||
#include "FSCommon.h"
|
||||
|
||||
#ifdef HAS_SDCARD
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
|
||||
|
||||
#ifdef SDCARD_USE_SPI1
|
||||
SPIClass SPI1(HSPI);
|
||||
#define SDHandler SPI1
|
||||
#endif
|
||||
|
||||
|
||||
#endif //HAS_SDCARD
|
||||
|
||||
bool copyFile(const char* from, const char* to)
|
||||
{
|
||||
@@ -169,3 +181,39 @@ void fsInit()
|
||||
listDir("/", 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void setupSDCard()
|
||||
{
|
||||
#ifdef HAS_SDCARD
|
||||
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
|
||||
if (!SD.begin(SDCARD_CS, SDHandler)) {
|
||||
DEBUG_MSG("No SD_MMC card detected\n");
|
||||
return ;
|
||||
}
|
||||
uint8_t cardType = SD.cardType();
|
||||
if (cardType == CARD_NONE) {
|
||||
DEBUG_MSG("No SD_MMC card attached\n");
|
||||
return ;
|
||||
}
|
||||
DEBUG_MSG("SD_MMC Card Type: ");
|
||||
if (cardType == CARD_MMC) {
|
||||
DEBUG_MSG("MMC\n");
|
||||
} else if (cardType == CARD_SD) {
|
||||
DEBUG_MSG("SDSC\n");
|
||||
} else if (cardType == CARD_SDHC) {
|
||||
DEBUG_MSG("SDHC\n");
|
||||
} else {
|
||||
DEBUG_MSG("UNKNOWN\n");
|
||||
}
|
||||
|
||||
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
|
||||
DEBUG_MSG("SD Card Size: %lluMB\n", cardSize);
|
||||
DEBUG_MSG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
|
||||
DEBUG_MSG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,3 +44,4 @@ bool copyFile(const char* from, const char* to);
|
||||
bool renameFile(const char* pathFrom, const char* pathTo);
|
||||
void listDir(const char * dirname, uint8_t levels, boolean del);
|
||||
void rmDir(const char * dirname);
|
||||
void setupSDCard();
|
||||
@@ -25,22 +25,6 @@ class GPSStatus : public Status
|
||||
public:
|
||||
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
||||
|
||||
// // proposed for deprecation
|
||||
// GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
|
||||
// uint32_t heading, uint32_t numSatellites)
|
||||
// : Status()
|
||||
// {
|
||||
// this->hasLock = hasLock;
|
||||
// this->isConnected = isConnected;
|
||||
|
||||
// this->p.latitude_i = latitude;
|
||||
// this->p.longitude_i = longitude;
|
||||
// this->p.altitude = altitude;
|
||||
// this->p.PDOP = dop;
|
||||
// this->p.ground_track = heading;
|
||||
// this->p.sats_in_view = numSatellites;
|
||||
// }
|
||||
|
||||
// preferred method
|
||||
GPSStatus(bool hasLock, bool isConnected, const Position &pos) : Status()
|
||||
{
|
||||
|
||||
+10
-26
@@ -2,22 +2,13 @@
|
||||
#include "configuration.h"
|
||||
#include "NodeDB.h"
|
||||
|
||||
#ifndef PIN_BUZZER
|
||||
|
||||
// Noop methods for boards w/o buzzer
|
||||
void playBeep(){};
|
||||
void playStartMelody(){};
|
||||
void playShutdownMelody(){};
|
||||
|
||||
#else
|
||||
#ifdef M5STACK
|
||||
#include "Speaker.h"
|
||||
TONE Tone;
|
||||
#else
|
||||
#if !defined(ARCH_ESP32) && !defined(ARCH_RP2040) && !defined(ARCH_PORTDUINO)
|
||||
#include "Tone.h"
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_PORTDUINO)
|
||||
extern "C" void delay(uint32_t dwMs);
|
||||
#endif
|
||||
|
||||
struct ToneDuration {
|
||||
int frequency_khz;
|
||||
@@ -43,30 +34,25 @@ const int DURATION_1_8 = 125; // 1/8 note
|
||||
const int DURATION_1_4 = 250; // 1/4 note
|
||||
|
||||
void playTones(const ToneDuration *tone_durations, int size) {
|
||||
if (config.network.eth_enabled != true) {
|
||||
#ifdef PIN_BUZZER
|
||||
if (!config.device.buzzer_gpio)
|
||||
config.device.buzzer_gpio = PIN_BUZZER;
|
||||
#endif
|
||||
if (config.device.buzzer_gpio) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
const auto &tone_duration = tone_durations[i];
|
||||
#ifdef M5STACK
|
||||
Tone.tone(tone_duration.frequency_khz);
|
||||
delay(tone_duration.duration_ms);
|
||||
Tone.mute();
|
||||
#else
|
||||
tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms);
|
||||
#endif
|
||||
tone(config.device.buzzer_gpio, tone_duration.frequency_khz, tone_duration.duration_ms);
|
||||
// to distinguish the notes, set a minimum time between them.
|
||||
delay(1.3 * tone_duration.duration_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef M5STACK
|
||||
|
||||
void playBeep() {
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
#else
|
||||
void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); }
|
||||
#endif
|
||||
|
||||
void playStartMelody() {
|
||||
ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8},
|
||||
@@ -75,11 +61,9 @@ void playStartMelody() {
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
|
||||
void playShutdownMelody() {
|
||||
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8},
|
||||
{NOTE_AS3, DURATION_1_8},
|
||||
{NOTE_FS3, DURATION_1_4}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
#endif
|
||||
@@ -110,6 +110,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define INA_ADDR_ALTERNATE 0x41
|
||||
#define QMC6310_ADDR 0x1C
|
||||
#define QMI8658_ADDR 0x6B
|
||||
#define QMC5883L_ADDR 0x1E
|
||||
#define SHTC3_ADDR 0x70
|
||||
#define LPS22HB_ADDR 0x5C
|
||||
#define LPS22HB_ADDR_ALT 0x5D
|
||||
|
||||
+55
-49
@@ -12,7 +12,7 @@
|
||||
|
||||
void printATECCInfo()
|
||||
{
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
atecc.readConfigZone(false);
|
||||
|
||||
DEBUG_MSG("ATECC608B Serial Number: ");
|
||||
@@ -90,7 +90,7 @@ uint8_t oled_probe(byte addr)
|
||||
return o_probe;
|
||||
}
|
||||
|
||||
void scanI2Cdevice(void)
|
||||
void scanI2Cdevice()
|
||||
{
|
||||
byte err, addr;
|
||||
uint16_t registerValue = 0x00;
|
||||
@@ -106,16 +106,16 @@ void scanI2Cdevice(void)
|
||||
if (addr == SSD1306_ADDRESS) {
|
||||
screen_found = addr;
|
||||
screen_model = oled_probe(addr);
|
||||
if (screen_model == 1){
|
||||
if (screen_model == 1) {
|
||||
DEBUG_MSG("ssd1306 display found\n");
|
||||
} else if (screen_model == 2){
|
||||
} else if (screen_model == 2) {
|
||||
DEBUG_MSG("sh1106 display found\n");
|
||||
} else {
|
||||
DEBUG_MSG("unknown display found\n");
|
||||
}
|
||||
}
|
||||
#ifndef ARCH_PORTDUINO
|
||||
if (addr == ATECC608B_ADDR){
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
if (addr == ATECC608B_ADDR) {
|
||||
keystore_found = addr;
|
||||
if (atecc.begin(keystore_found) == true) {
|
||||
DEBUG_MSG("ATECC608B initialized\n");
|
||||
@@ -163,50 +163,56 @@ void scanI2Cdevice(void)
|
||||
DEBUG_MSG("axp192/axp2101 PMU found\n");
|
||||
}
|
||||
#endif
|
||||
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
|
||||
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
|
||||
if (registerValue == 0x61) {
|
||||
DEBUG_MSG("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr;
|
||||
} else if (registerValue == 0x60) {
|
||||
DEBUG_MSG("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr;
|
||||
} else {
|
||||
DEBUG_MSG("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BMP280] = addr;
|
||||
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
|
||||
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
|
||||
if (registerValue == 0x61) {
|
||||
DEBUG_MSG("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr;
|
||||
} else if (registerValue == 0x60) {
|
||||
DEBUG_MSG("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr;
|
||||
} else {
|
||||
DEBUG_MSG("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BMP280] = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
|
||||
registerValue = getRegisterValue(addr, 0xFE, 2);
|
||||
DEBUG_MSG("Register MFG_UID: 0x%x\n", registerValue);
|
||||
if (registerValue == 0x5449) {
|
||||
DEBUG_MSG("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_INA260] = addr;
|
||||
} else { // Assume INA219 if INA260 ID is not found
|
||||
DEBUG_MSG("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_INA219] = addr;
|
||||
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
|
||||
registerValue = getRegisterValue(addr, 0xFE, 2);
|
||||
DEBUG_MSG("Register MFG_UID: 0x%x\n", registerValue);
|
||||
if (registerValue == 0x5449) {
|
||||
DEBUG_MSG("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_INA260] = addr;
|
||||
} else { // Assume INA219 if INA260 ID is not found
|
||||
DEBUG_MSG("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_INA219] = addr;
|
||||
}
|
||||
}
|
||||
if (addr == MCP9808_ADDR) {
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
|
||||
DEBUG_MSG("MCP9808 sensor found\n");
|
||||
}
|
||||
if (addr == SHTC3_ADDR) {
|
||||
DEBUG_MSG("SHTC3 sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_SHTC3] = addr;
|
||||
}
|
||||
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
|
||||
DEBUG_MSG("LPS22HB sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_LPS22] = addr;
|
||||
}
|
||||
|
||||
// High rate sensors, will be processed internally
|
||||
if (addr == QMC6310_ADDR) {
|
||||
DEBUG_MSG("QMC6310 Highrate 3-Axis magnetic sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMC6310] = addr;
|
||||
}
|
||||
if (addr == QMI8658_ADDR) {
|
||||
DEBUG_MSG("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658] = addr;
|
||||
}
|
||||
if (addr == QMC5883L_ADDR) {
|
||||
DEBUG_MSG("QMC5883L Highrate 3-Axis magnetic sensor found\n");
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMC5883L] = addr;
|
||||
}
|
||||
}
|
||||
if (addr == MCP9808_ADDR) {
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
|
||||
DEBUG_MSG("MCP9808 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
}
|
||||
if (addr == QMC6310_ADDR) {
|
||||
DEBUG_MSG("QMC6310 3-Axis magnetic sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMC6310] = addr;
|
||||
}
|
||||
if (addr == QMI8658_ADDR) {
|
||||
DEBUG_MSG("QMI8658 6-Axis inertial measurement sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658] = addr;
|
||||
}
|
||||
if (addr == SHTC3_ADDR) {
|
||||
DEBUG_MSG("SHTC3 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_SHTC3] = addr;
|
||||
}
|
||||
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
|
||||
DEBUG_MSG("LPS22HB sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_LPS22] = addr;
|
||||
}
|
||||
} else if (err == 4) {
|
||||
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
|
||||
}
|
||||
@@ -218,5 +224,5 @@ void scanI2Cdevice(void)
|
||||
DEBUG_MSG("%i I2C devices found\n",nDevices);
|
||||
}
|
||||
#else
|
||||
void scanI2Cdevice(void) {}
|
||||
void scanI2Cdevice() {}
|
||||
#endif
|
||||
|
||||
+14
-2
@@ -150,9 +150,21 @@ bool GPS::setupGPS()
|
||||
_serial_gps->setRxBufferSize(2048); // the default is 256
|
||||
#endif
|
||||
|
||||
// if the overrides are not dialled in, set them from the board definitions, if they exist
|
||||
|
||||
#if defined(GPS_RX_PIN)
|
||||
if (!config.position.rx_gpio)
|
||||
config.position.rx_gpio = GPS_RX_PIN;
|
||||
#endif
|
||||
#if defined(GPS_TX_PIN)
|
||||
if (!config.position.tx_gpio)
|
||||
config.position.tx_gpio = GPS_TX_PIN;
|
||||
#endif
|
||||
|
||||
// ESP32 has a special set of parameters vs other arduino ports
|
||||
#if defined(GPS_RX_PIN) && defined(ARCH_ESP32)
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
|
||||
#if defined(ARCH_ESP32)
|
||||
if(config.position.rx_gpio)
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, config.position.rx_gpio, config.position.tx_gpio);
|
||||
#else
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -109,7 +109,7 @@ bool NMEAGPS::lookForLocation()
|
||||
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
fixType = atoi(gsafixtype.value()); // will set to zero if no data
|
||||
DEBUG_MSG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
|
||||
// DEBUG_MSG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
|
||||
#endif
|
||||
|
||||
// check if GPS has an acceptable lock
|
||||
@@ -168,7 +168,7 @@ bool NMEAGPS::lookForLocation()
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
p.HDOP = reader.hdop.value();
|
||||
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
|
||||
DEBUG_MSG("PDOP=%d, HDOP=%d\n", dop, reader.hdop.value());
|
||||
// DEBUG_MSG("PDOP=%d, HDOP=%d\n", p.PDOP, p.HDOP);
|
||||
#else
|
||||
// FIXME! naive PDOP emulation (assumes VDOP==HDOP)
|
||||
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)
|
||||
|
||||
+20
-6
@@ -1,4 +1,5 @@
|
||||
#include "NMEAWPL.h"
|
||||
#include "GeoCoord.h"
|
||||
|
||||
/* -------------------------------------------
|
||||
* 1 2 3 4 5 6
|
||||
@@ -17,7 +18,15 @@
|
||||
|
||||
uint32_t printWPL(char *buf, const Position &pos, const char *name)
|
||||
{
|
||||
uint32_t len = sprintf(buf, "$GNWPL,%07.2f,%c,%08.2f,%c,%s", pos.latitude_i * 1e-5, pos.latitude_i < 0 ? 'S' : 'N', pos.longitude_i * 1e-5, pos.longitude_i < 0 ? 'W' : 'E', name);
|
||||
GeoCoord geoCoord(pos.latitude_i,pos.longitude_i,pos.altitude);
|
||||
uint32_t len = sprintf(buf, "$GNWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s",
|
||||
geoCoord.getDMSLatDeg(),
|
||||
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6,
|
||||
geoCoord.getDMSLatCP(),
|
||||
geoCoord.getDMSLonDeg(),
|
||||
(abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
|
||||
geoCoord.getDMSLonCP(),
|
||||
name);
|
||||
uint32_t chk = 0;
|
||||
for (uint32_t i = 1; i < len; i++) {
|
||||
chk ^= buf[i];
|
||||
@@ -52,15 +61,20 @@ uint32_t printWPL(char *buf, const Position &pos, const char *name)
|
||||
|
||||
uint32_t printGGA(char *buf, const Position &pos)
|
||||
{
|
||||
uint32_t len = sprintf(buf, "$GNGGA,%06u.%03u,%07.2f,%c,%08.2f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d",
|
||||
GeoCoord geoCoord(pos.latitude_i,pos.longitude_i,pos.altitude);
|
||||
uint32_t len = sprintf(buf, "$GNGGA,%06u.%03u,%02d%07.4f,%c,%03d%07.4f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d",
|
||||
pos.time / 1000,
|
||||
pos.time % 1000,
|
||||
pos.latitude_i * 1e-5, pos.latitude_i < 0 ? 'S' : 'N',
|
||||
pos.longitude_i * 1e-5, pos.longitude_i < 0 ? 'W' : 'E',
|
||||
geoCoord.getDMSLatDeg(),
|
||||
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6,
|
||||
geoCoord.getDMSLatCP(),
|
||||
geoCoord.getDMSLonDeg(),
|
||||
(abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
|
||||
geoCoord.getDMSLonCP(),
|
||||
pos.fix_type,
|
||||
pos.sats_in_view,
|
||||
pos.HDOP,
|
||||
pos.altitude,
|
||||
geoCoord.getAltitude(),
|
||||
'M',
|
||||
pos.altitude_geoidal_separation,
|
||||
'M',
|
||||
@@ -73,4 +87,4 @@ uint32_t printGGA(char *buf, const Position &pos)
|
||||
}
|
||||
len += sprintf(buf + len, "*%02X\r\n", chk);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -44,7 +44,11 @@ void readFromRTC()
|
||||
if(rtc_found == PCF8563_RTC) {
|
||||
uint32_t now = millis();
|
||||
PCF8563_Class rtc;
|
||||
#ifdef RTC_USE_WIRE1
|
||||
rtc.begin(Wire1);
|
||||
#else
|
||||
rtc.begin();
|
||||
#endif
|
||||
auto tc = rtc.getDateTime();
|
||||
tm t;
|
||||
t.tm_year = tc.year - 1900;
|
||||
@@ -110,7 +114,11 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
#elif defined(PCF8563_RTC)
|
||||
if(rtc_found == PCF8563_RTC) {
|
||||
PCF8563_Class rtc;
|
||||
rtc.begin();
|
||||
#ifdef RTC_USE_WIRE1
|
||||
rtc.begin(Wire1);
|
||||
#else
|
||||
rtc.begin();
|
||||
#endif
|
||||
tm *t = localtime(&tv->tv_sec);
|
||||
rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
|
||||
DEBUG_MSG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
|
||||
|
||||
+15
-14
@@ -283,27 +283,27 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
|
||||
|
||||
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
int x_offset = display->width() / 2;
|
||||
int y_offset = display->height() == 64 ? 0 : 32;
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(64 + x, y, "Bluetooth");
|
||||
display->drawString(x_offset + x, y_offset + y, "Bluetooth");
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Enter this code");
|
||||
y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM -4 : y_offset + FONT_HEIGHT_MEDIUM + 5;
|
||||
display->drawString(x_offset + x, y_offset + y, "Enter this code");
|
||||
|
||||
display->setFont(FONT_LARGE);
|
||||
String displayPin(btPIN);
|
||||
String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6);
|
||||
y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5;
|
||||
display->drawString(x_offset + x, y_offset + y, pin);
|
||||
|
||||
auto displayPin = new String(btPIN);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawString(12 + x, 26 + y, displayPin->substring(0, 3));
|
||||
display->drawString(72 + x, 26 + y, displayPin->substring(3, 6));
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_SMALL);
|
||||
char buf[30];
|
||||
const char *name = "Name: ";
|
||||
strcpy(buf, name);
|
||||
strcat(buf, getDeviceName());
|
||||
display->drawString(64 + x, 48 + y, buf);
|
||||
String deviceName = "Name: ";
|
||||
deviceName.concat(getDeviceName());
|
||||
y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5;
|
||||
display->drawString(x_offset + x, y_offset + y, deviceName);
|
||||
}
|
||||
|
||||
static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
@@ -538,9 +538,10 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else {
|
||||
|
||||
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
|
||||
|
||||
if (gpsFormat != Config_DisplayConfig_GpsCoordinateFormat_DMS) {
|
||||
char coordinateLine[22];
|
||||
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
|
||||
if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_DEC) { // Decimal Degrees
|
||||
sprintf(coordinateLine, "%f %f", geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7);
|
||||
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_UTM) { // Universal Transverse Mercator
|
||||
|
||||
+28
-18
@@ -87,8 +87,6 @@ uint8_t kb_model;
|
||||
// The I2C address of the RTC Module (if found)
|
||||
uint8_t rtc_found;
|
||||
|
||||
bool rIf_wide_lora = false;
|
||||
|
||||
// Keystore Chips
|
||||
uint8_t keystore_found;
|
||||
#ifndef ARCH_PORTDUINO
|
||||
@@ -102,7 +100,7 @@ uint32_t serialSinceMsec;
|
||||
bool pmu_found;
|
||||
|
||||
// Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan
|
||||
uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8_t nodeTelemetrySensorsMap[_TelemetrySensorType_MAX + 1] = { 0 }; // one is enough, missing elements will be initialized to 0 anyway.
|
||||
|
||||
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
|
||||
|
||||
@@ -142,8 +140,9 @@ bool ButtonThread::shutdown_on_long_stop = false;
|
||||
#endif
|
||||
|
||||
static Periodic *ledPeriodic;
|
||||
static OSThread *powerFSMthread, *buttonThread;
|
||||
static OSThread *powerFSMthread;
|
||||
#if HAS_BUTTON
|
||||
static OSThread *buttonThread;
|
||||
uint32_t ButtonThread::longPressTime = 0;
|
||||
#endif
|
||||
|
||||
@@ -246,8 +245,32 @@ void setup()
|
||||
digitalWrite(PIN_3V3_EN, 1);
|
||||
#endif
|
||||
|
||||
|
||||
// Currently only the tbeam has a PMU
|
||||
// PMU initialization needs to be placed before scanI2Cdevice
|
||||
power = new Power();
|
||||
power->setStatusHandler(powerStatus);
|
||||
powerStatus->observe(&power->newStatus);
|
||||
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
|
||||
|
||||
|
||||
#ifdef LILYGO_TBEAM_S3_CORE
|
||||
// In T-Beam-S3-core, the I2C device cannot be scanned before power initialization, otherwise the device will be stuck
|
||||
// PCF8563 RTC in tbeam-s3 uses Wire1 to share I2C bus
|
||||
Wire1.beginTransmission(PCF8563_RTC);
|
||||
if (Wire1.endTransmission() == 0){
|
||||
rtc_found = PCF8563_RTC;
|
||||
DEBUG_MSG("PCF8563 RTC found\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// We need to scan here to decide if we have a screen for nodeDB.init()
|
||||
scanI2Cdevice();
|
||||
|
||||
#ifdef HAS_SDCARD
|
||||
setupSDCard();
|
||||
#endif
|
||||
|
||||
#ifdef RAK4630
|
||||
// scanEInkDevice();
|
||||
#endif
|
||||
@@ -282,22 +305,10 @@ void setup()
|
||||
|
||||
playStartMelody();
|
||||
|
||||
// Currently only the tbeam has a PMU
|
||||
power = new Power();
|
||||
power->setStatusHandler(powerStatus);
|
||||
powerStatus->observe(&power->newStatus);
|
||||
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
|
||||
|
||||
/*
|
||||
* Repeat the scanning for I2C devices after power initialization or look for 'latecomers'.
|
||||
* Boards with an PMU need to be powered on to correctly scan to the device address, such as t-beam-s3-core
|
||||
*/
|
||||
scanI2Cdevice();
|
||||
|
||||
// fixed screen override?
|
||||
if (config.display.oled != Config_DisplayConfig_OledType_OLED_AUTO)
|
||||
screen_model = config.display.oled;
|
||||
|
||||
|
||||
// Init our SPI controller (must be before screen and lora)
|
||||
initSPI();
|
||||
#ifndef ARCH_ESP32
|
||||
@@ -385,7 +396,6 @@ void setup()
|
||||
rIf = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("SX1280 Radio init succeeded, using SX1280 radio\n");
|
||||
rIf_wide_lora = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-4
@@ -6,7 +6,7 @@
|
||||
#include "PowerStatus.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "mesh/generated/telemetry.pb.h"
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
#include <SparkFun_ATECCX08a_Arduino_Library.h>
|
||||
#endif
|
||||
|
||||
@@ -17,17 +17,16 @@ extern uint8_t kb_model;
|
||||
extern uint8_t rtc_found;
|
||||
extern uint8_t keystore_found;
|
||||
|
||||
extern bool rIf_wide_lora;
|
||||
extern bool eink_found;
|
||||
extern bool pmu_found;
|
||||
extern bool isCharging;
|
||||
extern bool isUSBPowered;
|
||||
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
extern ATECCX08A atecc;
|
||||
#endif
|
||||
|
||||
extern uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658+1];
|
||||
extern uint8_t nodeTelemetrySensorsMap[_TelemetrySensorType_MAX + 1];
|
||||
|
||||
extern int TCPPort; // set by Portduino
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@ template class SX126xInterface<SX1262>;
|
||||
template class SX126xInterface<SX1268>;
|
||||
template class SX126xInterface<LLCC68>;
|
||||
|
||||
#if !defined(ARCH_PORTDUINO)
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
template class SX128xInterface<SX1280>;
|
||||
#endif
|
||||
@@ -104,16 +104,17 @@ bool MeshService::reloadConfig(int saveWhat)
|
||||
}
|
||||
|
||||
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
||||
void MeshService::reloadOwner()
|
||||
void MeshService::reloadOwner(bool shouldSave)
|
||||
{
|
||||
// DEBUG_MSG("reloadOwner()\n");
|
||||
// update our local data directly
|
||||
nodeDB.updateUser(nodeDB.getNodeNum(), owner);
|
||||
assert(nodeInfoModule);
|
||||
// update everyone else
|
||||
if (nodeInfoModule)
|
||||
// update everyone else and save to disk
|
||||
if (nodeInfoModule && shouldSave) {
|
||||
nodeInfoModule->sendOurNodeInfo();
|
||||
nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
|
||||
nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,7 +69,7 @@ class MeshService
|
||||
bool reloadConfig(int saveWhat=SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
|
||||
|
||||
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
||||
void reloadOwner();
|
||||
void reloadOwner(bool shouldSave = true);
|
||||
|
||||
/// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least
|
||||
/// sends our owner
|
||||
|
||||
+16
-2
@@ -204,6 +204,7 @@ void NodeDB::installDefaultModuleConfig()
|
||||
{
|
||||
DEBUG_MSG("Installing default ModuleConfig\n");
|
||||
memset(&moduleConfig, 0, sizeof(ModuleConfig));
|
||||
|
||||
moduleConfig.version = DEVICESTATE_CUR_VER;
|
||||
moduleConfig.has_mqtt = true;
|
||||
moduleConfig.has_range_test = true;
|
||||
@@ -213,6 +214,10 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.has_external_notification = true;
|
||||
moduleConfig.has_canned_message = true;
|
||||
|
||||
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(default_mqtt_address));
|
||||
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(default_mqtt_username));
|
||||
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(default_mqtt_password));
|
||||
|
||||
initModuleConfigIntervals();
|
||||
}
|
||||
|
||||
@@ -470,6 +475,15 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
DEBUG_MSG("Error: can't rename new pref file\n");
|
||||
} else {
|
||||
DEBUG_MSG("Can't write prefs\n");
|
||||
#ifdef ARCH_NRF52
|
||||
static uint8_t failedCounter = 0;
|
||||
failedCounter++;
|
||||
if(failedCounter >= 2){
|
||||
FSCom.format();
|
||||
//After formatting, the device needs to be restarted
|
||||
nodeDB.resetRadioConfig(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
DEBUG_MSG("ERROR: Filesystem not implemented\n");
|
||||
@@ -741,9 +755,9 @@ void recordCriticalError(CriticalErrorCode code, uint32_t address, const char *f
|
||||
String lcd = String("Critical error ") + code + "!\n";
|
||||
screen->print(lcd.c_str());
|
||||
if (filename)
|
||||
DEBUG_MSG("NOTE! Recording critical error %d at %s:%lx\n", code, filename, address);
|
||||
DEBUG_MSG("NOTE! Recording critical error %d at %s:%lu\n", code, filename, address);
|
||||
else
|
||||
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address);
|
||||
DEBUG_MSG("NOTE! Recording critical error %d, address=0x%lx\n", code, address);
|
||||
|
||||
// Record error to DB
|
||||
myNodeInfo.error_code = code;
|
||||
|
||||
+5
-1
@@ -58,7 +58,7 @@ class NodeDB
|
||||
void init();
|
||||
|
||||
/// write to flash
|
||||
void saveToDisk(int saveWhat=SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS), saveChannelsToDisk(), saveDeviceStateToDisk();
|
||||
void saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS), saveChannelsToDisk(), saveDeviceStateToDisk();
|
||||
|
||||
/** Reinit radio config if needed, because either:
|
||||
* a) sometimes a buggy android app might send us bogus settings or
|
||||
@@ -194,6 +194,10 @@ extern NodeDB nodeDB;
|
||||
#define default_min_wake_secs 10
|
||||
#define default_screen_on_secs 60 * 10
|
||||
|
||||
#define default_mqtt_address "mqtt.meshtastic.org"
|
||||
#define default_mqtt_username "meshdev"
|
||||
#define default_mqtt_password "large4cats"
|
||||
|
||||
inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval)
|
||||
{
|
||||
if (configuredInterval > 0) return configuredInterval * 1000;
|
||||
|
||||
@@ -129,6 +129,7 @@ bool RF95Interface::reconfigure()
|
||||
|
||||
if (power > MAX_POWER) // This chip has lower power limits than some
|
||||
power = MAX_POWER;
|
||||
|
||||
err = lora->setOutputPower(power);
|
||||
if (err != RADIOLIB_ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);
|
||||
|
||||
+23
-14
@@ -89,7 +89,7 @@ const RegionInfo regions[] = {
|
||||
https://rrf.rsm.govt.nz/smart-web/smart/page/-smart/domain/licence/LicenceSummary.wdk?id=219752
|
||||
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
|
||||
*/
|
||||
RDEF(NZ_865, 864.0f, 868.0f, 100, 0, 0, true, false, false),
|
||||
RDEF(NZ_865, 864.0f, 868.0f, 100, 0, 36, true, false, false),
|
||||
|
||||
/*
|
||||
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
||||
@@ -177,7 +177,7 @@ uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
||||
static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
|
||||
uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader));
|
||||
// Make sure enough time has elapsed for this packet to be sent and an ACK is received.
|
||||
// Make sure enough time has elapsed for this packet to be sent and an ACK is received.
|
||||
// DEBUG_MSG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec);
|
||||
float channelUtil = airTime->channelUtilizationPercent();
|
||||
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
|
||||
@@ -189,7 +189,7 @@ uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
||||
uint32_t RadioInterface::getTxDelayMsec()
|
||||
{
|
||||
/** We wait a random multiple of 'slotTimes' (see definition in header file) in order to avoid collisions.
|
||||
The pool to take a random multiple from is the contention window (CW), which size depends on the
|
||||
The pool to take a random multiple from is the contention window (CW), which size depends on the
|
||||
current channel utilization. */
|
||||
float channelUtil = airTime->channelUtilizationPercent();
|
||||
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
|
||||
@@ -225,7 +225,7 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr)
|
||||
|
||||
void printPacket(const char *prefix, const MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff,
|
||||
DEBUG_MSG("%s (id=0x%08x fr=0x%02x to=0x%02x, WantAck=%d, HopLim=%d Ch=0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff,
|
||||
p->want_ack, p->hop_limit, p->channel);
|
||||
if (p->which_payload_variant == MeshPacket_decoded_tag) {
|
||||
auto &s = p->decoded;
|
||||
@@ -365,37 +365,37 @@ void RadioInterface::applyModemConfig()
|
||||
|
||||
switch (loraConfig.modem_preset) {
|
||||
case Config_LoRaConfig_ModemPreset_SHORT_FAST:
|
||||
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
|
||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
||||
cr = 8;
|
||||
sf = 7;
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_SHORT_SLOW:
|
||||
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
|
||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
||||
cr = 8;
|
||||
sf = 8;
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
|
||||
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
|
||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
||||
cr = 8;
|
||||
sf = 9;
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
|
||||
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
|
||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
||||
cr = 8;
|
||||
sf = 10;
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_LONG_FAST:
|
||||
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
|
||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
||||
cr = 8;
|
||||
sf = 11;
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_LONG_SLOW:
|
||||
bw = (myRegion->wideLora && rIf_wide_lora) ? 400 : 125;
|
||||
bw = (myRegion->wideLora) ? 406.25 : 125;
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
|
||||
bw = (myRegion->wideLora && rIf_wide_lora) ? 200 : 31.25;
|
||||
bw = (myRegion->wideLora) ? 203.125 : 31.25;
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
@@ -411,6 +411,14 @@ void RadioInterface::applyModemConfig()
|
||||
bw = 31.25;
|
||||
if (bw == 62) // Fix for 62.5Khz bandwidth
|
||||
bw = 62.5;
|
||||
if (bw == 200)
|
||||
bw = 203.125;
|
||||
if (bw == 400)
|
||||
bw = 406.25;
|
||||
if (bw == 800)
|
||||
bw = 812.5;
|
||||
if (bw == 1600)
|
||||
bw = 1625.0;
|
||||
}
|
||||
|
||||
power = loraConfig.tx_power;
|
||||
@@ -424,7 +432,7 @@ void RadioInterface::applyModemConfig()
|
||||
|
||||
// Set final tx_power back onto config
|
||||
loraConfig.tx_power = (int8_t)power; // cppcheck-suppress assignmentAddressToInteger
|
||||
|
||||
|
||||
// Calculate the number of channels
|
||||
uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000)));
|
||||
|
||||
@@ -441,9 +449,10 @@ void RadioInterface::applyModemConfig()
|
||||
saveChannelNum(channel_num);
|
||||
saveFreq(freq + config.lora.frequency_offset);
|
||||
|
||||
DEBUG_MSG("Radio freq=%.3f, config.lora.frequency_offset=%.3f\n", freq, config.lora.frequency_offset);
|
||||
DEBUG_MSG("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power);
|
||||
DEBUG_MSG("Radio myRegion->freqStart / myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart);
|
||||
DEBUG_MSG("Radio myRegion->numChannels: %d\n", numChannels);
|
||||
DEBUG_MSG("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart);
|
||||
DEBUG_MSG("Radio myRegion->numChannels: %d x %.3fkHz\n", numChannels, bw);
|
||||
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
|
||||
DEBUG_MSG("Radio frequency: %f\n", getFreq());
|
||||
DEBUG_MSG("Slot time: %u msec\n", slotTimeMsec);
|
||||
|
||||
@@ -11,17 +11,6 @@
|
||||
// FIXME, we default to 4MHz SPI, SPI mode 0, check if the datasheet says it can really do that
|
||||
static SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
|
||||
void LockingModule::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes)
|
||||
{
|
||||
concurrency::LockGuard g(spiLock);
|
||||
|
||||
Module::SPItransfer(cmd, reg, dataOut, dataIn, numBytes);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void LockingModule::SPIbeginTransaction()
|
||||
{
|
||||
spiLock->lock();
|
||||
@@ -36,8 +25,6 @@ void LockingModule::SPIendTransaction()
|
||||
Module::SPIendTransaction();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
RadioLibInterface::RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
|
||||
SPIClass &spi, PhysicalLayer *_iface)
|
||||
: NotifiedWorkerThread("RadioIf"), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface)
|
||||
|
||||
@@ -41,12 +41,8 @@ class LockingModule : public Module
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes) override;
|
||||
#else
|
||||
void SPIbeginTransaction() override;
|
||||
void SPIendTransaction() override;
|
||||
#endif
|
||||
};
|
||||
|
||||
class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread
|
||||
|
||||
@@ -96,7 +96,11 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
if (MeshModule::currentReply)
|
||||
DEBUG_MSG("Some other module has replied to this message, no need for a 2nd ack\n");
|
||||
else
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||
if (p->which_payload_variant == MeshPacket_decoded_tag)
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||
else
|
||||
// Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded
|
||||
sendAckNak(Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex());
|
||||
}
|
||||
|
||||
// We consider an ack to be either a !routing packet with a request ID or a routing packet with !error
|
||||
|
||||
@@ -12,6 +12,7 @@ SX126xInterface<T>::SX126xInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq,
|
||||
SPIClass &spi)
|
||||
: RadioLibInterface(cs, irq, rst, busy, spi, &lora), lora(&module)
|
||||
{
|
||||
DEBUG_MSG("SX126xInterface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
|
||||
}
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
@@ -25,11 +26,11 @@ bool SX126xInterface<T>::init()
|
||||
pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef SX126X_RXEN // set not rx or tx mode
|
||||
#if defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC) // set not rx or tx mode
|
||||
digitalWrite(SX126X_RXEN, LOW); // Set low before becoming an output
|
||||
pinMode(SX126X_RXEN, OUTPUT);
|
||||
#endif
|
||||
#ifdef SX126X_TXEN
|
||||
#if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
|
||||
digitalWrite(SX126X_TXEN, LOW);
|
||||
pinMode(SX126X_TXEN, OUTPUT);
|
||||
#endif
|
||||
@@ -56,9 +57,9 @@ bool SX126xInterface<T>::init()
|
||||
// \todo Display actual typename of the adapter, not just `SX126x`
|
||||
DEBUG_MSG("SX126x init result %d\n", res);
|
||||
|
||||
DEBUG_MSG("Frequency set to %f\n", getFreq());
|
||||
DEBUG_MSG("Bandwidth set to %f\n", bw);
|
||||
DEBUG_MSG("Power output set to %d\n", power);
|
||||
DEBUG_MSG("Frequency set to %f\n", getFreq());
|
||||
DEBUG_MSG("Bandwidth set to %f\n", bw);
|
||||
DEBUG_MSG("Power output set to %d\n", power);
|
||||
|
||||
// current limit was removed from module' ctor
|
||||
// override default value (60 mA)
|
||||
@@ -66,10 +67,10 @@ bool SX126xInterface<T>::init()
|
||||
DEBUG_MSG("Current limit set to %f\n", currentLimit);
|
||||
DEBUG_MSG("Current limit set result %d\n", res);
|
||||
|
||||
#ifdef SX126X_TXEN
|
||||
#if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
|
||||
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
|
||||
if (res == RADIOLIB_ERR_NONE)
|
||||
res = lora.setDio2AsRfSwitch(true);
|
||||
res = lora.setDio2AsRfSwitch(false);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
@@ -81,11 +82,11 @@ bool SX126xInterface<T>::init()
|
||||
|
||||
//if(crcLSB != 0x0f)
|
||||
// RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
|
||||
crcLSB = 0x5a;
|
||||
err = lora.writeRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != RADIOLIB_ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != RADIOLIB_ERR_NONE)
|
||||
@@ -144,8 +145,9 @@ bool SX126xInterface<T>::reconfigure()
|
||||
if (err != RADIOLIB_ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);
|
||||
|
||||
if (power > 22) // This chip has lower power limits than some
|
||||
power = 22;
|
||||
if (power > SX126X_MAX_POWER) // This chip has lower power limits than some
|
||||
power = SX126X_MAX_POWER;
|
||||
|
||||
err = lora.setOutputPower(power);
|
||||
assert(err == RADIOLIB_ERR_NONE);
|
||||
|
||||
@@ -164,14 +166,18 @@ template<typename T>
|
||||
void SX126xInterface<T>::setStandby()
|
||||
{
|
||||
checkNotification(); // handle any pending interrupts before we force standby
|
||||
|
||||
|
||||
int err = lora.standby();
|
||||
|
||||
if (err != RADIOLIB_ERR_NONE)
|
||||
DEBUG_MSG("SX126x standby failed with error %d\n", err);
|
||||
|
||||
assert(err == RADIOLIB_ERR_NONE);
|
||||
|
||||
#ifdef SX126X_RXEN // we have RXEN/TXEN control - turn off RX and TX power
|
||||
#if defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power
|
||||
digitalWrite(SX126X_RXEN, LOW);
|
||||
#endif
|
||||
#ifdef SX126X_TXEN
|
||||
#if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
|
||||
digitalWrite(SX126X_TXEN, LOW);
|
||||
#endif
|
||||
|
||||
@@ -196,10 +202,10 @@ void SX126xInterface<T>::addReceiveMetadata(MeshPacket *mp)
|
||||
template<typename T>
|
||||
void SX126xInterface<T>::configHardwareForSend()
|
||||
{
|
||||
#ifdef SX126X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power
|
||||
#if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on TX power / off RX power
|
||||
digitalWrite(SX126X_TXEN, HIGH);
|
||||
#endif
|
||||
#ifdef SX126X_RXEN
|
||||
#if defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC)
|
||||
digitalWrite(SX126X_RXEN, LOW);
|
||||
#endif
|
||||
|
||||
@@ -218,13 +224,13 @@ void SX126xInterface<T>::startReceive()
|
||||
|
||||
setStandby();
|
||||
|
||||
#ifdef SX126X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power
|
||||
#if defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on RX power / off TX power
|
||||
digitalWrite(SX126X_RXEN, HIGH);
|
||||
#endif
|
||||
#ifdef SX126X_TXEN
|
||||
#if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
|
||||
digitalWrite(SX126X_TXEN, LOW);
|
||||
#endif
|
||||
|
||||
|
||||
// int err = lora.startReceive();
|
||||
int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in
|
||||
// standby mostly.
|
||||
@@ -244,13 +250,13 @@ bool SX126xInterface<T>::isChannelActive()
|
||||
// check if we can detect a LoRa preamble on the current channel
|
||||
int16_t result;
|
||||
|
||||
setStandby();
|
||||
setStandby();
|
||||
result = lora.scanChannel();
|
||||
if (result == RADIOLIB_PREAMBLE_DETECTED)
|
||||
if (result == RADIOLIB_PREAMBLE_DETECTED)
|
||||
return true;
|
||||
|
||||
|
||||
assert(result != RADIOLIB_ERR_WRONG_MODEM);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "SX1280Interface.h"
|
||||
#include "error.h"
|
||||
|
||||
#if !defined(ARCH_PORTDUINO)
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
|
||||
SX1280Interface::SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
|
||||
SPIClass &spi)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Our adapter for SX1280 radios
|
||||
*/
|
||||
|
||||
#if !defined(ARCH_PORTDUINO)
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
|
||||
class SX1280Interface : public SX128xInterface<SX1280>
|
||||
{
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
#include "SX128xInterface.h"
|
||||
#include "error.h"
|
||||
|
||||
#if !defined(ARCH_PORTDUINO)
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
|
||||
// Particular boards might define a different max power based on what their hardware can do
|
||||
#ifndef SX128X_MAX_POWER
|
||||
#define SX128X_MAX_POWER 22
|
||||
#define SX128X_MAX_POWER 13
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
@@ -61,7 +61,7 @@ bool SX128xInterface<T>::init()
|
||||
#endif
|
||||
|
||||
if (res == RADIOLIB_ERR_NONE)
|
||||
res = lora.setCRC(RADIOLIB_SX128X_LORA_CRC_ON);
|
||||
res = lora.setCRC(2);
|
||||
|
||||
if (res == RADIOLIB_ERR_NONE)
|
||||
startReceive(); // start receiving
|
||||
@@ -105,8 +105,9 @@ bool SX128xInterface<T>::reconfigure()
|
||||
if (err != RADIOLIB_ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);
|
||||
|
||||
if (power > 22) // This chip has lower power limits than some
|
||||
power = 22;
|
||||
if (power > SX128X_MAX_POWER) // This chip has lower power limits than some
|
||||
power = SX128X_MAX_POWER;
|
||||
|
||||
err = lora.setOutputPower(power);
|
||||
assert(err == RADIOLIB_ERR_NONE);
|
||||
|
||||
@@ -218,7 +219,11 @@ bool SX128xInterface<T>::isChannelActive()
|
||||
template<typename T>
|
||||
bool SX128xInterface<T>::isActivelyReceiving()
|
||||
{
|
||||
return isChannelActive();
|
||||
// return isChannelActive();
|
||||
|
||||
uint16_t irq = lora.getIrqStatus();
|
||||
bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID);
|
||||
return hasPreamble;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(ARCH_PORTDUINO)
|
||||
#if defined(RADIOLIB_GODMODE)
|
||||
|
||||
#include "RadioLibInterface.h"
|
||||
|
||||
|
||||
@@ -82,10 +82,11 @@ typedef struct _AdminMessage {
|
||||
ModuleConfig set_module_config;
|
||||
/* Set the Canned Message Module messages text. */
|
||||
char set_canned_message_module_messages[201];
|
||||
/* Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins */
|
||||
bool confirm_set_config;
|
||||
/* Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins */
|
||||
bool confirm_set_module_config;
|
||||
/* Begins an edit transaction for config, module config, owner, and channel settings changes
|
||||
This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */
|
||||
bool begin_edit_settings;
|
||||
/* Commits an open transaction for any edits made to config, module config, owner, and channel settings */
|
||||
bool commit_edit_settings;
|
||||
/* Setting channels/radio config remotely carries the risk that you might send an invalid config and the radio never talks to your mesh again.
|
||||
Therefore if setting either of these properties remotely, you must send a confirm_xxx message within 10 minutes.
|
||||
If you fail to do so, the radio will assume loss of comms and revert your changes.
|
||||
@@ -147,8 +148,8 @@ extern "C" {
|
||||
#define AdminMessage_set_config_tag 34
|
||||
#define AdminMessage_set_module_config_tag 35
|
||||
#define AdminMessage_set_canned_message_module_messages_tag 36
|
||||
#define AdminMessage_confirm_set_config_tag 64
|
||||
#define AdminMessage_confirm_set_module_config_tag 65
|
||||
#define AdminMessage_begin_edit_settings_tag 64
|
||||
#define AdminMessage_commit_edit_settings_tag 65
|
||||
#define AdminMessage_confirm_set_channel_tag 66
|
||||
#define AdminMessage_confirm_set_radio_tag 67
|
||||
#define AdminMessage_reboot_ota_seconds_tag 95
|
||||
@@ -177,8 +178,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 3
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_module_config,set_module_config), 35) \
|
||||
X(a, STATIC, ONEOF, STRING, (payload_variant,set_canned_message_module_messages,set_canned_message_module_messages), 36) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_config,confirm_set_config), 64) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_module_config,confirm_set_module_config), 65) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_channel,confirm_set_channel), 66) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_radio,confirm_set_radio), 67) \
|
||||
X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \
|
||||
|
||||
@@ -100,6 +100,8 @@ typedef struct _Config_DeviceConfig {
|
||||
Config_DeviceConfig_Role role;
|
||||
bool serial_enabled;
|
||||
bool debug_log_enabled;
|
||||
uint32_t button_gpio;
|
||||
uint32_t buzzer_gpio;
|
||||
} Config_DeviceConfig;
|
||||
|
||||
typedef struct _Config_DisplayConfig {
|
||||
@@ -143,6 +145,8 @@ typedef struct _Config_PositionConfig {
|
||||
uint32_t gps_update_interval;
|
||||
uint32_t gps_attempt_time;
|
||||
uint32_t position_flags;
|
||||
uint32_t rx_gpio;
|
||||
uint32_t tx_gpio;
|
||||
} Config_PositionConfig;
|
||||
|
||||
typedef struct _Config_PowerConfig {
|
||||
@@ -225,8 +229,8 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define Config_init_default {0, {Config_DeviceConfig_init_default}}
|
||||
#define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0}
|
||||
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
|
||||
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_default {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default}
|
||||
#define Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
|
||||
@@ -234,8 +238,8 @@ extern "C" {
|
||||
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||
#define Config_BluetoothConfig_init_default {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
|
||||
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0}
|
||||
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
|
||||
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define Config_NetworkConfig_init_zero {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero}
|
||||
#define Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
|
||||
@@ -250,6 +254,8 @@ extern "C" {
|
||||
#define Config_DeviceConfig_role_tag 1
|
||||
#define Config_DeviceConfig_serial_enabled_tag 2
|
||||
#define Config_DeviceConfig_debug_log_enabled_tag 3
|
||||
#define Config_DeviceConfig_button_gpio_tag 4
|
||||
#define Config_DeviceConfig_buzzer_gpio_tag 5
|
||||
#define Config_DisplayConfig_screen_on_secs_tag 1
|
||||
#define Config_DisplayConfig_gps_format_tag 2
|
||||
#define Config_DisplayConfig_auto_screen_carousel_secs_tag 3
|
||||
@@ -280,6 +286,8 @@ extern "C" {
|
||||
#define Config_PositionConfig_gps_update_interval_tag 5
|
||||
#define Config_PositionConfig_gps_attempt_time_tag 6
|
||||
#define Config_PositionConfig_position_flags_tag 7
|
||||
#define Config_PositionConfig_rx_gpio_tag 8
|
||||
#define Config_PositionConfig_tx_gpio_tag 9
|
||||
#define Config_PowerConfig_is_power_saving_tag 1
|
||||
#define Config_PowerConfig_on_battery_shutdown_after_secs_tag 2
|
||||
#define Config_PowerConfig_adc_multiplier_override_tag 3
|
||||
@@ -325,7 +333,9 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,bluetooth,payload_variant.bl
|
||||
#define Config_DeviceConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, role, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, serial_enabled, 2) \
|
||||
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 3)
|
||||
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, button_gpio, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, buzzer_gpio, 5)
|
||||
#define Config_DeviceConfig_CALLBACK NULL
|
||||
#define Config_DeviceConfig_DEFAULT NULL
|
||||
|
||||
@@ -336,7 +346,9 @@ X(a, STATIC, SINGULAR, BOOL, fixed_position, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, gps_enabled, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, position_flags, 7)
|
||||
X(a, STATIC, SINGULAR, UINT32, position_flags, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, rx_gpio, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, tx_gpio, 9)
|
||||
#define Config_PositionConfig_CALLBACK NULL
|
||||
#define Config_PositionConfig_DEFAULT NULL
|
||||
|
||||
@@ -429,12 +441,12 @@ extern const pb_msgdesc_t Config_BluetoothConfig_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define Config_BluetoothConfig_size 10
|
||||
#define Config_DeviceConfig_size 6
|
||||
#define Config_DeviceConfig_size 18
|
||||
#define Config_DisplayConfig_size 22
|
||||
#define Config_LoRaConfig_size 68
|
||||
#define Config_NetworkConfig_IpV4Config_size 20
|
||||
#define Config_NetworkConfig_size 161
|
||||
#define Config_PositionConfig_size 30
|
||||
#define Config_PositionConfig_size 42
|
||||
#define Config_PowerConfig_size 43
|
||||
#define Config_size 164
|
||||
|
||||
|
||||
@@ -150,8 +150,8 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
|
||||
#define LocalModuleConfig_fields &LocalModuleConfig_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define LocalConfig_size 361
|
||||
#define LocalModuleConfig_size 294
|
||||
#define LocalConfig_size 385
|
||||
#define LocalModuleConfig_size 361
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -78,6 +78,10 @@ typedef enum _HardwareModel {
|
||||
HardwareModel_DR_DEV = 41,
|
||||
/* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/ */
|
||||
HardwareModel_M5STACK = 42,
|
||||
/* New Heltec LoRA32 with ESP32-S3 CPU */
|
||||
HardwareModel_HELTEC_V3 = 43,
|
||||
/* New Heltec Wireless Stick Lite with ESP32-S3 CPU */
|
||||
HardwareModel_HELTEC_WSL_V3 = 44,
|
||||
/* Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. */
|
||||
HardwareModel_PRIVATE_HW = 255
|
||||
} HardwareModel;
|
||||
@@ -501,7 +505,7 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
|
||||
typedef struct _MeshPacket {
|
||||
/* The sending node number.
|
||||
Note: Our crypto implementation uses this field as well.
|
||||
See [crypto](/docs/about/overview/encryption) for details.
|
||||
See [crypto](/docs/overview/encryption) for details.
|
||||
FIXME - really should be fixed32 instead, this encoding only hurts the ble link though. */
|
||||
uint32_t from;
|
||||
/* The (immediatSee Priority description for more details.y should be fixed32 instead, this encoding only
|
||||
@@ -529,7 +533,7 @@ typedef struct _MeshPacket {
|
||||
needs to be unique for a few minutes (long enough to last for the length of
|
||||
any ACK or the completion of a mesh broadcast flood).
|
||||
Note: Our crypto implementation uses this id as well.
|
||||
See [crypto](/docs/about/overview/encryption) for details.
|
||||
See [crypto](/docs/overview/encryption) for details.
|
||||
FIXME - really should be fixed32 instead, this encoding only
|
||||
hurts the ble link though. */
|
||||
uint32_t id;
|
||||
|
||||
@@ -90,13 +90,14 @@ typedef struct _ModuleConfig_ExternalNotificationConfig {
|
||||
bool active;
|
||||
bool alert_message;
|
||||
bool alert_bell;
|
||||
bool use_pwm;
|
||||
} ModuleConfig_ExternalNotificationConfig;
|
||||
|
||||
typedef struct _ModuleConfig_MQTTConfig {
|
||||
bool enabled;
|
||||
char address[32];
|
||||
char username[32];
|
||||
char password[32];
|
||||
char username[64];
|
||||
char password[64];
|
||||
bool encryption_enabled;
|
||||
bool json_enabled;
|
||||
} ModuleConfig_MQTTConfig;
|
||||
@@ -184,7 +185,7 @@ extern "C" {
|
||||
#define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0}
|
||||
#define ModuleConfig_AudioConfig_init_default {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN}
|
||||
#define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
|
||||
#define ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0}
|
||||
@@ -193,7 +194,7 @@ extern "C" {
|
||||
#define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0}
|
||||
#define ModuleConfig_AudioConfig_init_zero {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN}
|
||||
#define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
|
||||
#define ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
|
||||
#define ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0}
|
||||
@@ -222,6 +223,7 @@ extern "C" {
|
||||
#define ModuleConfig_ExternalNotificationConfig_active_tag 4
|
||||
#define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5
|
||||
#define ModuleConfig_ExternalNotificationConfig_alert_bell_tag 6
|
||||
#define ModuleConfig_ExternalNotificationConfig_use_pwm_tag 7
|
||||
#define ModuleConfig_MQTTConfig_enabled_tag 1
|
||||
#define ModuleConfig_MQTTConfig_address_tag 2
|
||||
#define ModuleConfig_MQTTConfig_username_tag 3
|
||||
@@ -314,7 +316,8 @@ X(a, STATIC, SINGULAR, UINT32, output_ms, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, output, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, active, 4) \
|
||||
X(a, STATIC, SINGULAR, BOOL, alert_message, 5) \
|
||||
X(a, STATIC, SINGULAR, BOOL, alert_bell, 6)
|
||||
X(a, STATIC, SINGULAR, BOOL, alert_bell, 6) \
|
||||
X(a, STATIC, SINGULAR, BOOL, use_pwm, 7)
|
||||
#define ModuleConfig_ExternalNotificationConfig_CALLBACK NULL
|
||||
#define ModuleConfig_ExternalNotificationConfig_DEFAULT NULL
|
||||
|
||||
@@ -382,13 +385,13 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg;
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define ModuleConfig_AudioConfig_size 22
|
||||
#define ModuleConfig_CannedMessageConfig_size 49
|
||||
#define ModuleConfig_ExternalNotificationConfig_size 20
|
||||
#define ModuleConfig_MQTTConfig_size 105
|
||||
#define ModuleConfig_ExternalNotificationConfig_size 22
|
||||
#define ModuleConfig_MQTTConfig_size 169
|
||||
#define ModuleConfig_RangeTestConfig_size 10
|
||||
#define ModuleConfig_SerialConfig_size 26
|
||||
#define ModuleConfig_StoreForwardConfig_size 22
|
||||
#define ModuleConfig_TelemetryConfig_size 18
|
||||
#define ModuleConfig_size 107
|
||||
#define ModuleConfig_size 172
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -33,7 +33,9 @@ typedef enum _TelemetrySensorType {
|
||||
/* 3-Axis magnetic sensor */
|
||||
TelemetrySensorType_QMC6310 = 9,
|
||||
/* 6-Axis inertial measurement sensor */
|
||||
TelemetrySensorType_QMI8658 = 10
|
||||
TelemetrySensorType_QMI8658 = 10,
|
||||
/* 3-Axis magnetic sensor */
|
||||
TelemetrySensorType_QMC5883L = 11
|
||||
} TelemetrySensorType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -85,8 +87,8 @@ typedef struct _Telemetry {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _TelemetrySensorType_MIN TelemetrySensorType_SENSOR_UNSET
|
||||
#define _TelemetrySensorType_MAX TelemetrySensorType_QMI8658
|
||||
#define _TelemetrySensorType_ARRAYSIZE ((TelemetrySensorType)(TelemetrySensorType_QMI8658+1))
|
||||
#define _TelemetrySensorType_MAX TelemetrySensorType_QMC5883L
|
||||
#define _TelemetrySensorType_ARRAYSIZE ((TelemetrySensorType)(TelemetrySensorType_QMC5883L+1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <HTTPBodyParser.hpp>
|
||||
#include <HTTPMultipartBodyParser.hpp>
|
||||
#include <HTTPURLEncodedBodyParser.hpp>
|
||||
#include <json11.hpp>
|
||||
#include "mqtt/JSON.h"
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
@@ -246,15 +246,15 @@ void htmlDeleteDir(const char *dirname)
|
||||
root.close();
|
||||
}
|
||||
|
||||
std::vector<std::map<char *, char *>> *htmlListDir(std::vector<std::map<char *, char *>> *fileList, const char *dirname,
|
||||
uint8_t levels)
|
||||
JSONArray htmlListDir(const char *dirname, uint8_t levels)
|
||||
{
|
||||
File root = FSCom.open(dirname, FILE_O_READ);
|
||||
JSONArray fileList;
|
||||
if (!root) {
|
||||
return NULL;
|
||||
return fileList;
|
||||
}
|
||||
if (!root.isDirectory()) {
|
||||
return NULL;
|
||||
return fileList;
|
||||
}
|
||||
|
||||
// iterate over the file list
|
||||
@@ -263,19 +263,19 @@ std::vector<std::map<char *, char *>> *htmlListDir(std::vector<std::map<char *,
|
||||
if (file.isDirectory() && !String(file.name()).endsWith(".")) {
|
||||
if (levels) {
|
||||
#ifdef ARCH_ESP32
|
||||
htmlListDir(fileList, file.path(), levels - 1);
|
||||
fileList.push_back(new JSONValue(htmlListDir(file.path(), levels - 1)));
|
||||
#else
|
||||
htmlListDir(fileList, file.name(), levels - 1);
|
||||
fileList.push_back(new JSONValue(htmlListDir(file.name(), levels - 1)));
|
||||
#endif
|
||||
file.close();
|
||||
}
|
||||
} else {
|
||||
std::map<char *, char *> thisFileMap;
|
||||
thisFileMap[strdup("size")] = strdup(String(file.size()).c_str());
|
||||
JSONObject thisFileMap;
|
||||
thisFileMap["size"] = new JSONValue((int)file.size());
|
||||
#ifdef ARCH_ESP32
|
||||
thisFileMap[strdup("name")] = strdup(String(file.path()).substring(1).c_str());
|
||||
thisFileMap["name"] = new JSONValue(String(file.path()).substring(1).c_str());
|
||||
#else
|
||||
thisFileMap[strdup("name")] = strdup(String(file.name()).substring(1).c_str());
|
||||
thisFileMap["name"] = new JSONValue(String(file.name()).substring(1).c_str());
|
||||
#endif
|
||||
if (String(file.name()).substring(1).endsWith(".gz")) {
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -284,9 +284,9 @@ std::vector<std::map<char *, char *>> *htmlListDir(std::vector<std::map<char *,
|
||||
String modifiedFile = String(file.name()).substring(1);
|
||||
#endif
|
||||
modifiedFile.remove((modifiedFile.length() - 3), 3);
|
||||
thisFileMap[strdup("nameModified")] = strdup(modifiedFile.c_str());
|
||||
thisFileMap["nameModified"] = new JSONValue(modifiedFile.c_str());
|
||||
}
|
||||
fileList->push_back(thisFileMap);
|
||||
fileList.push_back(new JSONValue(thisFileMap));
|
||||
}
|
||||
file.close();
|
||||
file = root.openNextFile();
|
||||
@@ -301,29 +301,31 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
res->setHeader("Access-Control-Allow-Methods", "GET");
|
||||
|
||||
using namespace json11;
|
||||
auto fileList = htmlListDir(new std::vector<std::map<char *, char *>>(), "/static", 10);
|
||||
auto fileList = htmlListDir("/static", 10);
|
||||
|
||||
// create json output structure
|
||||
Json filesystemObj = Json::object{
|
||||
{"total", String(FSCom.totalBytes()).c_str()},
|
||||
{"used", String(FSCom.usedBytes()).c_str()},
|
||||
{"free", String(FSCom.totalBytes() - FSCom.usedBytes()).c_str()},
|
||||
};
|
||||
JSONObject filesystemObj;
|
||||
filesystemObj["total"] = new JSONValue((int)FSCom.totalBytes());
|
||||
filesystemObj["used"] = new JSONValue((int)FSCom.usedBytes());
|
||||
filesystemObj["free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));
|
||||
|
||||
Json jsonObjInner = Json::object{{"files", Json(*fileList)}, {"filesystem", filesystemObj}};
|
||||
JSONObject jsonObjInner;
|
||||
jsonObjInner["files"] = new JSONValue(fileList);
|
||||
jsonObjInner["filesystem"] = new JSONValue(filesystemObj);
|
||||
|
||||
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}};
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["data"] = new JSONValue(jsonObjInner);
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
|
||||
// serialize and write it to the stream
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
|
||||
res->print(value->Stringify().c_str());
|
||||
|
||||
delete value;
|
||||
}
|
||||
|
||||
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
ResourceParameters *params = req->getParams();
|
||||
std::string paramValDelete;
|
||||
|
||||
@@ -334,15 +336,19 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
std::string pathDelete = "/" + paramValDelete;
|
||||
if (FSCom.remove(pathDelete.c_str())) {
|
||||
Serial.println(pathDelete.c_str());
|
||||
Json jsonObjOuter = Json::object{{"status", "ok"}};
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
return;
|
||||
} else {
|
||||
Serial.println(pathDelete.c_str());
|
||||
Json jsonObjOuter = Json::object{{"status", "Error"}};
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["status"] = new JSONValue("Error");
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -559,8 +565,6 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
|
||||
|
||||
void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
ResourceParameters *params = req->getParams();
|
||||
std::string content;
|
||||
|
||||
@@ -579,81 +583,87 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
}
|
||||
|
||||
// data->airtime->tx_log
|
||||
std::vector<String> txLogValues;
|
||||
JSONArray txLogValues;
|
||||
uint32_t *logArray;
|
||||
logArray = airTime->airtimeReport(TX_LOG);
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
uint32_t tmp;
|
||||
tmp = *(logArray + i);
|
||||
txLogValues.push_back(String(tmp));
|
||||
txLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
|
||||
// data->airtime->rx_log
|
||||
std::vector<String> rxLogValues;
|
||||
JSONArray rxLogValues;
|
||||
logArray = airTime->airtimeReport(RX_LOG);
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
uint32_t tmp;
|
||||
tmp = *(logArray + i);
|
||||
rxLogValues.push_back(String(tmp));
|
||||
rxLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
|
||||
// data->airtime->rx_all_log
|
||||
std::vector<String> rxAllLogValues;
|
||||
JSONArray rxAllLogValues;
|
||||
logArray = airTime->airtimeReport(RX_ALL_LOG);
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
uint32_t tmp;
|
||||
tmp = *(logArray + i);
|
||||
rxAllLogValues.push_back(String(tmp));
|
||||
rxAllLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
|
||||
Json jsonObjAirtime = Json::object{
|
||||
{"tx_log", Json(txLogValues)},
|
||||
{"rx_log", Json(rxLogValues)},
|
||||
{"rx_all_log", Json(rxAllLogValues)},
|
||||
{"channel_utilization", Json(airTime->channelUtilizationPercent())},
|
||||
{"utilization_tx", Json(airTime->utilizationTXPercent())},
|
||||
{"seconds_since_boot", Json(int(airTime->getSecondsSinceBoot()))},
|
||||
{"seconds_per_period", Json(int(airTime->getSecondsPerPeriod()))},
|
||||
{"periods_to_log", Json(airTime->getPeriodsToLog())},
|
||||
};
|
||||
// data->airtime
|
||||
JSONObject jsonObjAirtime;
|
||||
jsonObjAirtime["tx_log"] = new JSONValue(txLogValues);
|
||||
jsonObjAirtime["rx_log"] = new JSONValue(rxLogValues);
|
||||
jsonObjAirtime["rx_all_log"] = new JSONValue(rxAllLogValues);
|
||||
jsonObjAirtime["channel_utilization"] = new JSONValue(airTime->channelUtilizationPercent());
|
||||
jsonObjAirtime["utilization_tx"] = new JSONValue(airTime->utilizationTXPercent());
|
||||
jsonObjAirtime["seconds_since_boot"] = new JSONValue(int(airTime->getSecondsSinceBoot()));
|
||||
jsonObjAirtime["seconds_per_period"] = new JSONValue(int(airTime->getSecondsPerPeriod()));
|
||||
jsonObjAirtime["periods_to_log"] = new JSONValue(airTime->getPeriodsToLog());
|
||||
|
||||
// data->wifi
|
||||
String ipStr = String(WiFi.localIP().toString());
|
||||
|
||||
Json jsonObjWifi = Json::object{{"rssi", String(WiFi.RSSI())}, {"ip", ipStr.c_str()}};
|
||||
JSONObject jsonObjWifi;
|
||||
jsonObjWifi["rssi"] = new JSONValue(WiFi.RSSI());
|
||||
jsonObjWifi["ip"] = new JSONValue(WiFi.localIP().toString().c_str());
|
||||
|
||||
// data->memory
|
||||
Json jsonObjMemory = Json::object{{"heap_total", Json(int(ESP.getHeapSize()))},
|
||||
{"heap_free", Json(int(ESP.getFreeHeap()))},
|
||||
{"psram_total", Json(int(ESP.getPsramSize()))},
|
||||
{"psram_free", Json(int(ESP.getFreePsram()))},
|
||||
{"fs_total", String(FSCom.totalBytes()).c_str()},
|
||||
{"fs_used", String(FSCom.usedBytes()).c_str()},
|
||||
{"fs_free", String(FSCom.totalBytes() - FSCom.usedBytes()).c_str()}};
|
||||
JSONObject jsonObjMemory;
|
||||
jsonObjMemory["heap_total"] = new JSONValue((int)ESP.getHeapSize());
|
||||
jsonObjMemory["heap_free"] = new JSONValue((int)ESP.getFreeHeap());
|
||||
jsonObjMemory["psram_total"] = new JSONValue((int)ESP.getPsramSize());
|
||||
jsonObjMemory["psram_free"] = new JSONValue((int)ESP.getFreePsram());
|
||||
jsonObjMemory["fs_total"] = new JSONValue((int)FSCom.totalBytes());
|
||||
jsonObjMemory["fs_used"] = new JSONValue((int)FSCom.usedBytes());
|
||||
jsonObjMemory["fs_free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));
|
||||
|
||||
// data->power
|
||||
Json jsonObjPower = Json::object{{"battery_percent", Json(powerStatus->getBatteryChargePercent())},
|
||||
{"battery_voltage_mv", Json(powerStatus->getBatteryVoltageMv())},
|
||||
{"has_battery", BoolToString(powerStatus->getHasBattery())},
|
||||
{"has_usb", BoolToString(powerStatus->getHasUSB())},
|
||||
{"is_charging", BoolToString(powerStatus->getIsCharging())}};
|
||||
JSONObject jsonObjPower;
|
||||
jsonObjPower["battery_percent"] = new JSONValue(powerStatus->getBatteryChargePercent());
|
||||
jsonObjPower["battery_voltage_mv"] = new JSONValue(powerStatus->getBatteryVoltageMv());
|
||||
jsonObjPower["has_battery"] = new JSONValue(BoolToString(powerStatus->getHasBattery()));
|
||||
jsonObjPower["has_usb"] = new JSONValue(BoolToString(powerStatus->getHasUSB()));
|
||||
jsonObjPower["is_charging"] = new JSONValue(BoolToString(powerStatus->getIsCharging()));
|
||||
|
||||
// data->device
|
||||
Json jsonObjDevice = Json::object{{"reboot_counter", Json(int(myNodeInfo.reboot_count))}};
|
||||
JSONObject jsonObjDevice;
|
||||
jsonObjDevice["reboot_counter"] = new JSONValue((int)myNodeInfo.reboot_count);
|
||||
|
||||
// data->radio
|
||||
Json jsonObjRadio = Json::object{{"frequency", Json(RadioLibInterface::instance->getFreq())},
|
||||
{"lora_channel", Json(int(RadioLibInterface::instance->getChannelNum()))}};
|
||||
JSONObject jsonObjRadio;
|
||||
jsonObjRadio["frequency"] = new JSONValue(RadioLibInterface::instance->getFreq());
|
||||
jsonObjRadio["lora_channel"] = new JSONValue((int)RadioLibInterface::instance->getChannelNum());
|
||||
|
||||
// collect data to inner data object
|
||||
Json jsonObjInner = Json::object{{"airtime", jsonObjAirtime}, {"wifi", jsonObjWifi}, {"memory", jsonObjMemory},
|
||||
{"power", jsonObjPower}, {"device", jsonObjDevice}, {"radio", jsonObjRadio}};
|
||||
JSONObject jsonObjInner;
|
||||
jsonObjInner["airtime"] = new JSONValue(jsonObjAirtime);
|
||||
jsonObjInner["wifi"] = new JSONValue(jsonObjWifi);
|
||||
jsonObjInner["memory"] = new JSONValue(jsonObjMemory);
|
||||
jsonObjInner["power"] = new JSONValue(jsonObjPower);
|
||||
jsonObjInner["device"] = new JSONValue(jsonObjDevice);
|
||||
jsonObjInner["radio"] = new JSONValue(jsonObjRadio);
|
||||
|
||||
// create json output structure
|
||||
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}};
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["data"] = new JSONValue(jsonObjInner);
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
// serialize and write it to the stream
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -767,8 +777,6 @@ void handleRestart(HTTPRequest *req, HTTPResponse *res)
|
||||
|
||||
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
res->setHeader("Content-Type", "application/json");
|
||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
res->setHeader("Access-Control-Allow-Methods", "POST");
|
||||
@@ -797,15 +805,15 @@ void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
|
||||
#endif
|
||||
}
|
||||
|
||||
Json jsonObjOuter = Json::object{{"status", "ok"}};
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
|
||||
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
res->setHeader("Content-Type", "application/json");
|
||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||
res->setHeader("Access-Control-Allow-Methods", "GET");
|
||||
@@ -814,7 +822,7 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||
int n = WiFi.scanNetworks();
|
||||
|
||||
// build list of network objects
|
||||
std::vector<Json> networkObjs;
|
||||
JSONArray networkObjs;
|
||||
if (n > 0) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
char ssidArray[50];
|
||||
@@ -823,8 +831,10 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||
ssidString.toCharArray(ssidArray, 50);
|
||||
|
||||
if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) {
|
||||
Json thisNetwork = Json::object{{"ssid", ssidArray}, {"rssi", WiFi.RSSI(i)}};
|
||||
networkObjs.push_back(thisNetwork);
|
||||
JSONObject thisNetwork;
|
||||
thisNetwork["ssid"] = new JSONValue(ssidArray);
|
||||
thisNetwork["rssi"] = new JSONValue(WiFi.RSSI(i));
|
||||
networkObjs.push_back(new JSONValue(thisNetwork));
|
||||
}
|
||||
// Yield some cpu cycles to IP stack.
|
||||
// This is important in case the list is large and it takes us time to return
|
||||
@@ -834,9 +844,12 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||
}
|
||||
|
||||
// build output structure
|
||||
Json jsonObjOuter = Json::object{{"data", networkObjs}, {"status", "ok"}};
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["data"] = new JSONValue(networkObjs);
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
|
||||
// serialize and write it to the stream
|
||||
std::string jsonStr = jsonObjOuter.dump();
|
||||
res->print(jsonStr.c_str());
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
|
||||
@@ -35,32 +35,49 @@ char ourHost[16];
|
||||
|
||||
bool APStartupComplete = 0;
|
||||
|
||||
unsigned long lastrun_ntp = 0;
|
||||
|
||||
static bool needReconnect = true; // If we create our reconnector, run it once at the beginning
|
||||
|
||||
static Periodic *wifiReconnect;
|
||||
|
||||
static int32_t reconnectWiFi()
|
||||
{
|
||||
const char *wifiName = config.network.wifi_ssid;
|
||||
const char *wifiPsw = config.network.wifi_psk;
|
||||
|
||||
if (config.network.wifi_enabled && needReconnect && !WiFi.isConnected()) {
|
||||
if (config.network.wifi_enabled && needReconnect) {
|
||||
|
||||
if (!*wifiPsw) // Treat empty password as no password
|
||||
wifiPsw = NULL;
|
||||
|
||||
if (*wifiName) {
|
||||
needReconnect = false;
|
||||
needReconnect = false;
|
||||
|
||||
// Make sure we clear old connection credentials
|
||||
WiFi.disconnect(false, true);
|
||||
// Make sure we clear old connection credentials
|
||||
WiFi.disconnect(false, true);
|
||||
|
||||
DEBUG_MSG("... Reconnecting to WiFi access point\n");
|
||||
DEBUG_MSG("... Reconnecting to WiFi access point %s\n",wifiName);
|
||||
|
||||
int n = WiFi.scanNetworks();
|
||||
|
||||
if (n > 0) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
DEBUG_MSG("Found WiFi network %s, signal strength %d\n", WiFi.SSID(i).c_str(), WiFi.RSSI(i));
|
||||
yield();
|
||||
}
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.begin(wifiName, wifiPsw);
|
||||
} else {
|
||||
DEBUG_MSG("No networks found during site survey. Rebooting MCU...\n");
|
||||
screen->startRebootScreen();
|
||||
rebootAtMsec = millis() + 5000;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifndef DISABLE_NTP
|
||||
if (WiFi.isConnected()) {
|
||||
if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours
|
||||
DEBUG_MSG("Updating NTP time\n");
|
||||
if (timeClient.update()) {
|
||||
DEBUG_MSG("NTP Request Success - Setting RTCQualityNTP if needed\n");
|
||||
@@ -70,6 +87,7 @@ static int32_t reconnectWiFi()
|
||||
tv.tv_usec = 0;
|
||||
|
||||
perhapsSetRTC(RTCQualityNTP, &tv);
|
||||
lastrun_ntp = millis();
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("NTP Update failed\n");
|
||||
@@ -77,11 +95,13 @@ static int32_t reconnectWiFi()
|
||||
}
|
||||
#endif
|
||||
|
||||
return 43200 * 1000; // every 12 hours
|
||||
if (config.network.wifi_enabled && !WiFi.isConnected()) {
|
||||
return 1000; // check once per second
|
||||
} else {
|
||||
return 300000; // every 5 minutes
|
||||
}
|
||||
}
|
||||
|
||||
static Periodic *wifiReconnect;
|
||||
|
||||
bool isWifiAvailable()
|
||||
{
|
||||
|
||||
@@ -95,20 +115,10 @@ bool isWifiAvailable()
|
||||
// Disable WiFi
|
||||
void deinitWifi()
|
||||
{
|
||||
/*
|
||||
Note from Jm (jm@casler.org - Sept 16, 2020):
|
||||
|
||||
A bug in the ESP32 SDK was introduced in Oct 2019 that keeps the WiFi radio from
|
||||
turning back on after it's shut off. See:
|
||||
https://github.com/espressif/arduino-esp32/issues/3522
|
||||
|
||||
Until then, WiFi should only be allowed when there's no power
|
||||
saving on the 2.4g transceiver.
|
||||
*/
|
||||
|
||||
DEBUG_MSG("WiFi deinit\n");
|
||||
|
||||
if (isWifiAvailable()) {
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_MODE_NULL);
|
||||
DEBUG_MSG("WiFi Turned Off\n");
|
||||
// WiFi.printDiag(Serial);
|
||||
@@ -169,7 +179,7 @@ bool initWifi()
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.setHostname(ourHost);
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.setAutoReconnect(false);
|
||||
WiFi.setSleep(false);
|
||||
if (config.network.eth_mode == Config_NetworkConfig_EthMode_STATIC && config.network.ipv4_config.ip != 0) {
|
||||
WiFi.config(config.network.ipv4_config.ip,
|
||||
@@ -231,7 +241,9 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
DEBUG_MSG("Disconnected from WiFi access point\n");
|
||||
WiFi.disconnect(false, true);
|
||||
needReconnect = true;
|
||||
wifiReconnect->setIntervalFromNow(1000);
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
|
||||
DEBUG_MSG("Authentication mode of access point has changed\n");
|
||||
@@ -243,7 +255,9 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_LOST_IP:
|
||||
DEBUG_MSG("Lost IP address and IP address is reset to 0\n");
|
||||
WiFi.disconnect(false, true);
|
||||
needReconnect = true;
|
||||
wifiReconnect->setIntervalFromNow(1000);
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
|
||||
DEBUG_MSG("WiFi Protected Setup (WPS): succeeded in enrollee mode\n");
|
||||
@@ -259,7 +273,6 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
break;
|
||||
case SYSTEM_EVENT_AP_START:
|
||||
DEBUG_MSG("WiFi access point started\n");
|
||||
onNetworkConnected();
|
||||
break;
|
||||
case SYSTEM_EVENT_AP_STOP:
|
||||
DEBUG_MSG("WiFi access point stopped\n");
|
||||
|
||||
+44
-14
@@ -13,7 +13,10 @@
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_REBOOT_SECONDS 5
|
||||
|
||||
AdminModule *adminModule;
|
||||
bool hasOpenEditTransaction;
|
||||
|
||||
/// A special reserved string to indicate strings we can not share with external nodes. We will use this 'reserved' word instead.
|
||||
/// Also, to make setting work correctly, if someone tries to set a string to this reserved value we assume they don't really want
|
||||
@@ -133,13 +136,23 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
|
||||
case AdminMessage_factory_reset_tag: {
|
||||
DEBUG_MSG("Initiating factory reset\n");
|
||||
nodeDB.factoryReset();
|
||||
reboot(5);
|
||||
reboot(DEFAULT_REBOOT_SECONDS);
|
||||
break;
|
||||
}
|
||||
case AdminMessage_nodedb_reset_tag: {
|
||||
} case AdminMessage_nodedb_reset_tag: {
|
||||
DEBUG_MSG("Initiating node-db reset\n");
|
||||
nodeDB.resetNodes();
|
||||
reboot(5);
|
||||
reboot(DEFAULT_REBOOT_SECONDS);
|
||||
break;
|
||||
}
|
||||
case AdminMessage_begin_edit_settings_tag: {
|
||||
DEBUG_MSG("Beginning transaction for editing settings\n");
|
||||
hasOpenEditTransaction = true;
|
||||
break;
|
||||
}
|
||||
case AdminMessage_commit_edit_settings_tag: {
|
||||
DEBUG_MSG("Committing transaction for edited settings\n");
|
||||
hasOpenEditTransaction = false;
|
||||
saveChanges(SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
|
||||
break;
|
||||
}
|
||||
#ifdef ARCH_PORTDUINO
|
||||
@@ -163,6 +176,12 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// If asked for a response and it is not yet set, generate an 'ACK' response
|
||||
if (mp.decoded.want_response && !myReply) {
|
||||
myReply = allocErrorResponse(Routing_Error_NONE, &mp);
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
@@ -192,9 +211,8 @@ void AdminModule::handleSetOwner(const User &o)
|
||||
}
|
||||
|
||||
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
|
||||
service.reloadOwner();
|
||||
DEBUG_MSG("Rebooting due to owner changes\n");
|
||||
reboot(5);
|
||||
service.reloadOwner(!hasOpenEditTransaction);
|
||||
saveChanges(SEGMENT_DEVICESTATE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +238,7 @@ void AdminModule::handleSetConfig(const Config &c)
|
||||
config.has_position = true;
|
||||
config.position = c.payload_variant.position;
|
||||
// Save nodedb as well in case we got a fixed position packet
|
||||
nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
|
||||
saveChanges(SEGMENT_DEVICESTATE, false);
|
||||
break;
|
||||
case Config_power_tag:
|
||||
DEBUG_MSG("Setting config: Power\n");
|
||||
@@ -252,9 +270,8 @@ void AdminModule::handleSetConfig(const Config &c)
|
||||
config.bluetooth = c.payload_variant.bluetooth;
|
||||
break;
|
||||
}
|
||||
|
||||
service.reloadConfig(SEGMENT_CONFIG);
|
||||
reboot(5);
|
||||
|
||||
saveChanges(SEGMENT_CONFIG);
|
||||
}
|
||||
|
||||
void AdminModule::handleSetModuleConfig(const ModuleConfig &c)
|
||||
@@ -302,15 +319,14 @@ void AdminModule::handleSetModuleConfig(const ModuleConfig &c)
|
||||
break;
|
||||
}
|
||||
|
||||
service.reloadConfig(SEGMENT_MODULECONFIG);
|
||||
reboot(5);
|
||||
saveChanges(SEGMENT_MODULECONFIG);
|
||||
}
|
||||
|
||||
void AdminModule::handleSetChannel(const Channel &cc)
|
||||
{
|
||||
channels.setChannel(cc);
|
||||
channels.onConfigChanged(); // tell the radios about this change
|
||||
nodeDB.saveChannelsToDisk();
|
||||
saveChanges(SEGMENT_CHANNELS, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -479,6 +495,20 @@ void AdminModule::reboot(int32_t seconds)
|
||||
rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000);
|
||||
}
|
||||
|
||||
void AdminModule::saveChanges(int saveWhat, bool shouldReboot)
|
||||
{
|
||||
if (!hasOpenEditTransaction) {
|
||||
DEBUG_MSG("Saving changes to disk\n");
|
||||
service.reloadConfig(saveWhat); // Calls saveToDisk among other things
|
||||
} else {
|
||||
DEBUG_MSG("Delaying save of changes to disk until the open transaction is committed\n");
|
||||
}
|
||||
if (shouldReboot)
|
||||
{
|
||||
reboot(DEFAULT_REBOOT_SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
AdminModule::AdminModule() : ProtobufModule("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "ProtobufModule.h"
|
||||
|
||||
/**
|
||||
* Routing module for router control messages
|
||||
* Admin module for admin messages
|
||||
*/
|
||||
class AdminModule : public ProtobufModule<AdminMessage>
|
||||
{
|
||||
@@ -20,6 +20,9 @@ class AdminModule : public ProtobufModule<AdminMessage>
|
||||
virtual bool handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *p) override;
|
||||
|
||||
private:
|
||||
bool hasOpenEditTransaction = false;
|
||||
|
||||
void saveChanges(int saveWhat, bool shouldReboot = true);
|
||||
/**
|
||||
* Getters
|
||||
*/
|
||||
|
||||
@@ -176,7 +176,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
DEBUG_MSG("Canned message event Matrix key pressed\n");
|
||||
// this will send the text immediately on matrix press
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_SELECT;
|
||||
this->payload = event->kbchar;
|
||||
this->payload = MATRIXKEY;
|
||||
this->currentMessageIndex = event->kbchar -1;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
@@ -246,7 +246,12 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
} else {
|
||||
if ((this->messagesCount > this->currentMessageIndex) && (strlen(this->messages[this->currentMessageIndex]) > 0)) {
|
||||
sendText(NODENUM_BROADCAST, this->messages[this->currentMessageIndex], true);
|
||||
if(strcmp (this->messages[this->currentMessageIndex], "~") == 0) {
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
return INT32_MAX;
|
||||
} else {
|
||||
sendText(NODENUM_BROADCAST, this->messages[this->currentMessageIndex], true);
|
||||
}
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
|
||||
} else {
|
||||
DEBUG_MSG("Reset message is empty.\n");
|
||||
|
||||
@@ -76,7 +76,7 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
// moduleConfig.external_notification.output_ms = 1000;
|
||||
// moduleConfig.external_notification.output = 13;
|
||||
|
||||
if (externalCurrentState) {
|
||||
if (externalCurrentState && !moduleConfig.external_notification.use_pwm) {
|
||||
|
||||
// If the output is turned on, turn it back off after the given period of time.
|
||||
if (externalTurnedOn + (moduleConfig.external_notification.output_ms
|
||||
@@ -84,13 +84,13 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
|
||||
millis()) {
|
||||
DEBUG_MSG("Turning off external notification\n");
|
||||
if (output != PIN_BUZZER) {
|
||||
setExternalOff();
|
||||
}
|
||||
setExternalOff();
|
||||
}
|
||||
}
|
||||
|
||||
return (25);
|
||||
if (moduleConfig.external_notification.use_pwm)
|
||||
return INT32_MAX; // we don't need this thread here...
|
||||
else
|
||||
return 25;
|
||||
}
|
||||
|
||||
void ExternalNotificationModule::setExternalOn()
|
||||
@@ -129,11 +129,6 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
// moduleConfig.external_notification.output_ms = 1000;
|
||||
// moduleConfig.external_notification.output = 13;
|
||||
|
||||
if (moduleConfig.external_notification.alert_message) {
|
||||
// restrict to the gpio channel for rx
|
||||
boundChannel = Channels::gpioChannel;
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
|
||||
DEBUG_MSG("Initializing External Notification Module\n");
|
||||
@@ -142,14 +137,19 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
? moduleConfig.external_notification.output
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT;
|
||||
|
||||
if (output != PIN_BUZZER) {
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
// Set the direction of a pin
|
||||
DEBUG_MSG("Using Pin %i in digital mode\n", output);
|
||||
pinMode(output, OUTPUT);
|
||||
// Turn off the pin
|
||||
setExternalOff();
|
||||
} else{
|
||||
DEBUG_MSG("Using Pin %i in PWM mode\n", output);
|
||||
} else {
|
||||
config.device.buzzer_gpio = config.device.buzzer_gpio
|
||||
? config.device.buzzer_gpio
|
||||
: PIN_BUZZER;
|
||||
|
||||
// in PWM Mode we force the buzzer pin if it is set
|
||||
DEBUG_MSG("Using Pin %i in PWM mode\n", config.device.buzzer_gpio);
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("External Notification Module Disabled\n");
|
||||
@@ -170,7 +170,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
||||
DEBUG_MSG("externalNotificationModule - Notification Bell\n");
|
||||
for (int i = 0; i < p.payload.size; i++) {
|
||||
if (p.payload.bytes[i] == ASCII_BELL) {
|
||||
if (output != PIN_BUZZER) {
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn();
|
||||
} else {
|
||||
playBeep();
|
||||
@@ -181,7 +181,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
||||
|
||||
if (moduleConfig.external_notification.alert_message) {
|
||||
DEBUG_MSG("externalNotificationModule - Notification Module\n");
|
||||
if (output != PIN_BUZZER) {
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn();
|
||||
} else {
|
||||
playBeep();
|
||||
|
||||
@@ -21,8 +21,9 @@
|
||||
1) Enable the module by setting audio.codec2_enabled to 1.
|
||||
2) Set the pins (audio.mic_pin / audio.amp_pin) for your preferred microphone and amplifier GPIO pins.
|
||||
On tbeam, recommend to use:
|
||||
audio.mic_chan 7 (GPIO 35)
|
||||
audio.amp_pin 25 (GPIO 25)
|
||||
audio.mic_chan 6 (GPIO 34)
|
||||
audio.amp_pin 14
|
||||
audio.ptt_pin 39
|
||||
3) Set audio.timeout to the amount of time to wait before we consider
|
||||
your voice stream as "done".
|
||||
4) Set audio.bitrate to the desired codec2 rate (CODEC2_3200, CODEC2_2400, CODEC2_1600, CODEC2_1400, CODEC2_1300, CODEC2_1200, CODEC2_700, CODEC2_700B)
|
||||
@@ -33,8 +34,8 @@
|
||||
* Will not work on NRF and the Linux device targets.
|
||||
*/
|
||||
|
||||
#define AMIC 7
|
||||
#define AAMP 25
|
||||
#define AMIC 6
|
||||
#define AAMP 14
|
||||
#define PTT_PIN 39
|
||||
|
||||
#define AUDIO_MODULE_RX_BUFFER 128
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//#include <assert.h>
|
||||
|
||||
/*
|
||||
As a sender, I can send packets every n-seonds. These packets include an incramented PacketID.
|
||||
As a sender, I can send packets every n seconds. These packets include an incremented PacketID.
|
||||
As a receiver, I can receive packets from multiple senders. These packets can be saved to the Filesystem.
|
||||
*/
|
||||
|
||||
@@ -36,12 +36,12 @@ int32_t RangeTestModule::runOnce()
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
//moduleConfig.range_test.enabled = 1;
|
||||
//moduleConfig.range_test.sender = 30;
|
||||
// moduleConfig.range_test.enabled = 1;
|
||||
// moduleConfig.range_test.sender = 30;
|
||||
// moduleConfig.range_test.save = 1;
|
||||
|
||||
// Fixed position is useful when testing indoors.
|
||||
// radioConfig.preferences.fixed_position = 1;
|
||||
// config.position.fixed_position = 1;
|
||||
|
||||
uint32_t senderHeartbeat = moduleConfig.range_test.sender * 1000;
|
||||
|
||||
@@ -57,7 +57,8 @@ int32_t RangeTestModule::runOnce()
|
||||
return (5000); // Sending first message 5 seconds after initilization.
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Range Test Module -- Receiver\n");
|
||||
return (500);
|
||||
return (INT32_MAX);
|
||||
// This thread does not need to run as a receiver
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -70,8 +71,7 @@ int32_t RangeTestModule::runOnce()
|
||||
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("pref.fixed_position() %d\n", config.position.fixed_position);
|
||||
DEBUG_MSG("fixed_position() %d\n", config.position.fixed_position);
|
||||
|
||||
// Only send packets if the channel is less than 25% utilized.
|
||||
if (airTime->channelUtilizationPercent() < 25) {
|
||||
@@ -82,11 +82,11 @@ int32_t RangeTestModule::runOnce()
|
||||
|
||||
return (senderHeartbeat);
|
||||
} else {
|
||||
// Otherwise, we're a receiver.
|
||||
|
||||
return (500);
|
||||
return (INT32_MAX);
|
||||
// This thread does not need to run as a receiver
|
||||
}
|
||||
// TBD
|
||||
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -155,8 +155,8 @@ ProcessMessage RangeTestModuleRadio::handleReceived(const MeshPacket &mp)
|
||||
DEBUG_MSG("mp.from %d\n", mp.from);
|
||||
DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr);
|
||||
DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit);
|
||||
DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated
|
||||
DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated
|
||||
// DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated
|
||||
// DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated
|
||||
DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n");
|
||||
DEBUG_MSG("n->user.long_name %s\n", n->user.long_name);
|
||||
DEBUG_MSG("n->user.short_name %s\n", n->user.short_name);
|
||||
@@ -221,6 +221,8 @@ bool RangeTestModuleRadio::appendFile(const MeshPacket &mp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
FSCom.mkdir("/static");
|
||||
|
||||
// If the file doesn't exist, write the header.
|
||||
if (!FSCom.exists("/static/rangetest.csv")) {
|
||||
//--------- Write to file
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* File JSON.cpp part of the SimpleJSON Library - http://mjpa.in/json
|
||||
*
|
||||
* Copyright (C) 2010 Mike Anchor
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "JSON.h"
|
||||
|
||||
/**
|
||||
* Blocks off the public constructor
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
*/
|
||||
JSON::JSON()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a complete JSON encoded string
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param char* data The JSON text
|
||||
*
|
||||
* @return JSONValue* Returns a JSON Value representing the root, or NULL on error
|
||||
*/
|
||||
JSONValue *JSON::Parse(const char *data)
|
||||
{
|
||||
// Skip any preceding whitespace, end of data = no JSON = fail
|
||||
if (!SkipWhitespace(&data))
|
||||
return NULL;
|
||||
|
||||
// We need the start of a value here now...
|
||||
JSONValue *value = JSONValue::Parse(&data);
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
|
||||
// Can be white space now and should be at the end of the string then...
|
||||
if (SkipWhitespace(&data))
|
||||
{
|
||||
delete value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We're now at the end of the string
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the passed in JSONValue into a JSON encode string
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param JSONValue* value The root value
|
||||
*
|
||||
* @return std::string Returns a JSON encoded string representation of the given value
|
||||
*/
|
||||
std::string JSON::Stringify(const JSONValue *value)
|
||||
{
|
||||
if (value != NULL)
|
||||
return value->Stringify();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over any whitespace characters (space, tab, \r or \n) defined by the JSON spec
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the JSON text
|
||||
*
|
||||
* @return bool Returns true if there is more data, or false if the end of the text was reached
|
||||
*/
|
||||
bool JSON::SkipWhitespace(const char **data)
|
||||
{
|
||||
while (**data != 0 && (**data == ' ' || **data == '\t' || **data == '\r' || **data == '\n'))
|
||||
(*data)++;
|
||||
|
||||
return **data != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a JSON String as defined by the spec - "<some chars>"
|
||||
* Any escaped characters are swapped out for their unescaped values
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the JSON text
|
||||
* @param std::string& str Reference to a std::string to receive the extracted string
|
||||
*
|
||||
* @return bool Returns true on success, false on failure
|
||||
*/
|
||||
bool JSON::ExtractString(const char **data, std::string &str)
|
||||
{
|
||||
str = "";
|
||||
|
||||
while (**data != 0)
|
||||
{
|
||||
// Save the char so we can change it if need be
|
||||
char next_char = **data;
|
||||
|
||||
// Escaping something?
|
||||
if (next_char == '\\')
|
||||
{
|
||||
// Move over the escape char
|
||||
(*data)++;
|
||||
|
||||
// Deal with the escaped char
|
||||
switch (**data)
|
||||
{
|
||||
case '"': next_char = '"'; break;
|
||||
case '\\': next_char = '\\'; break;
|
||||
case '/': next_char = '/'; break;
|
||||
case 'b': next_char = '\b'; break;
|
||||
case 'f': next_char = '\f'; break;
|
||||
case 'n': next_char = '\n'; break;
|
||||
case 'r': next_char = '\r'; break;
|
||||
case 't': next_char = '\t'; break;
|
||||
case 'u':
|
||||
{
|
||||
// We need 5 chars (4 hex + the 'u') or its not valid
|
||||
if (!simplejson_csnlen(*data, 5))
|
||||
return false;
|
||||
|
||||
// Deal with the chars
|
||||
next_char = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// Do it first to move off the 'u' and leave us on the
|
||||
// final hex digit as we move on by one later on
|
||||
(*data)++;
|
||||
|
||||
next_char <<= 4;
|
||||
|
||||
// Parse the hex digit
|
||||
if (**data >= '0' && **data <= '9')
|
||||
next_char |= (**data - '0');
|
||||
else if (**data >= 'A' && **data <= 'F')
|
||||
next_char |= (10 + (**data - 'A'));
|
||||
else if (**data >= 'a' && **data <= 'f')
|
||||
next_char |= (10 + (**data - 'a'));
|
||||
else
|
||||
{
|
||||
// Invalid hex digit = invalid JSON
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// By the spec, only the above cases are allowed
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// End of the string?
|
||||
else if (next_char == '"')
|
||||
{
|
||||
(*data)++;
|
||||
str.reserve(); // Remove unused capacity
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disallowed char?
|
||||
else if (next_char < ' ' && next_char != '\t')
|
||||
{
|
||||
// SPEC Violation: Allow tabs due to real world cases
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the next char
|
||||
str += next_char;
|
||||
|
||||
// Move on
|
||||
(*data)++;
|
||||
}
|
||||
|
||||
// If we're here, the string ended incorrectly
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses some text as though it is an integer
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the JSON text
|
||||
*
|
||||
* @return double Returns the double value of the number found
|
||||
*/
|
||||
double JSON::ParseInt(const char **data)
|
||||
{
|
||||
double integer = 0;
|
||||
while (**data != 0 && **data >= '0' && **data <= '9')
|
||||
integer = integer * 10 + (*(*data)++ - '0');
|
||||
|
||||
return integer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses some text as though it is a decimal
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the JSON text
|
||||
*
|
||||
* @return double Returns the double value of the decimal found
|
||||
*/
|
||||
double JSON::ParseDecimal(const char **data)
|
||||
{
|
||||
double decimal = 0.0;
|
||||
double factor = 0.1;
|
||||
while (**data != 0 && **data >= '0' && **data <= '9')
|
||||
{
|
||||
int digit = (*(*data)++ - '0');
|
||||
decimal = decimal + digit * factor;
|
||||
factor *= 0.1;
|
||||
}
|
||||
return decimal;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* File JSON.h part of the SimpleJSON Library - http://mjpa.in/json
|
||||
*
|
||||
* Copyright (C) 2010 Mike Anchor
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _JSON_H_
|
||||
#define _JSON_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
|
||||
// Simple function to check a string 's' has at least 'n' characters
|
||||
static inline bool simplejson_csnlen(const char *s, size_t n) {
|
||||
if (s == 0)
|
||||
return false;
|
||||
|
||||
const char *save = s;
|
||||
while (n-- > 0)
|
||||
{
|
||||
if (*(save++) == 0) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Custom types
|
||||
class JSONValue;
|
||||
typedef std::vector<JSONValue*> JSONArray;
|
||||
typedef std::map<std::string, JSONValue*> JSONObject;
|
||||
|
||||
#include "JSONValue.h"
|
||||
|
||||
class JSON
|
||||
{
|
||||
friend class JSONValue;
|
||||
|
||||
public:
|
||||
static JSONValue* Parse(const char *data);
|
||||
static std::string Stringify(const JSONValue *value);
|
||||
protected:
|
||||
static bool SkipWhitespace(const char **data);
|
||||
static bool ExtractString(const char **data, std::string &str);
|
||||
static double ParseInt(const char **data);
|
||||
static double ParseDecimal(const char **data);
|
||||
private:
|
||||
JSON();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,940 @@
|
||||
/*
|
||||
* File JSONValue.cpp part of the SimpleJSON Library - http://mjpa.in/json
|
||||
*
|
||||
* Copyright (C) 2010 Mike Anchor
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
|
||||
#include "JSONValue.h"
|
||||
|
||||
// Macros to free an array/object
|
||||
#define FREE_ARRAY(x) { JSONArray::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete *iter; } }
|
||||
#define FREE_OBJECT(x) { JSONObject::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete (*iter).second; } }
|
||||
|
||||
/**
|
||||
* Parses a JSON encoded value to a JSONValue object
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @param char** data Pointer to a char* that contains the data
|
||||
*
|
||||
* @return JSONValue* Returns a pointer to a JSONValue object on success, NULL on error
|
||||
*/
|
||||
JSONValue *JSONValue::Parse(const char **data)
|
||||
{
|
||||
// Is it a string?
|
||||
if (**data == '"')
|
||||
{
|
||||
std::string str;
|
||||
if (!JSON::ExtractString(&(++(*data)), str))
|
||||
return NULL;
|
||||
else
|
||||
return new JSONValue(str);
|
||||
}
|
||||
|
||||
// Is it a boolean?
|
||||
else if ((simplejson_csnlen(*data, 4) && strncasecmp(*data, "true", 4) == 0) || (simplejson_csnlen(*data, 5) && strncasecmp(*data, "false", 5) == 0))
|
||||
{
|
||||
bool value = strncasecmp(*data, "true", 4) == 0;
|
||||
(*data) += value ? 4 : 5;
|
||||
return new JSONValue(value);
|
||||
}
|
||||
|
||||
// Is it a null?
|
||||
else if (simplejson_csnlen(*data, 4) && strncasecmp(*data, "null", 4) == 0)
|
||||
{
|
||||
(*data) += 4;
|
||||
return new JSONValue();
|
||||
}
|
||||
|
||||
// Is it a number?
|
||||
else if (**data == '-' || (**data >= '0' && **data <= '9'))
|
||||
{
|
||||
// Negative?
|
||||
bool neg = **data == '-';
|
||||
if (neg) (*data)++;
|
||||
|
||||
double number = 0.0;
|
||||
|
||||
// Parse the whole part of the number - only if it wasn't 0
|
||||
if (**data == '0')
|
||||
(*data)++;
|
||||
else if (**data >= '1' && **data <= '9')
|
||||
number = JSON::ParseInt(data);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
// Could be a decimal now...
|
||||
if (**data == '.')
|
||||
{
|
||||
(*data)++;
|
||||
|
||||
// Not get any digits?
|
||||
if (!(**data >= '0' && **data <= '9'))
|
||||
return NULL;
|
||||
|
||||
// Find the decimal and sort the decimal place out
|
||||
// Use ParseDecimal as ParseInt won't work with decimals less than 0.1
|
||||
// thanks to Javier Abadia for the report & fix
|
||||
double decimal = JSON::ParseDecimal(data);
|
||||
|
||||
// Save the number
|
||||
number += decimal;
|
||||
}
|
||||
|
||||
// Could be an exponent now...
|
||||
if (**data == 'E' || **data == 'e')
|
||||
{
|
||||
(*data)++;
|
||||
|
||||
// Check signage of expo
|
||||
bool neg_expo = false;
|
||||
if (**data == '-' || **data == '+')
|
||||
{
|
||||
neg_expo = **data == '-';
|
||||
(*data)++;
|
||||
}
|
||||
|
||||
// Not get any digits?
|
||||
if (!(**data >= '0' && **data <= '9'))
|
||||
return NULL;
|
||||
|
||||
// Sort the expo out
|
||||
double expo = JSON::ParseInt(data);
|
||||
for (double i = 0.0; i < expo; i++)
|
||||
number = neg_expo ? (number / 10.0) : (number * 10.0);
|
||||
}
|
||||
|
||||
// Was it neg?
|
||||
if (neg) number *= -1;
|
||||
|
||||
return new JSONValue(number);
|
||||
}
|
||||
|
||||
// An object?
|
||||
else if (**data == '{')
|
||||
{
|
||||
JSONObject object;
|
||||
|
||||
(*data)++;
|
||||
|
||||
while (**data != 0)
|
||||
{
|
||||
// Whitespace at the start?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Special case - empty object
|
||||
if (object.size() == 0 && **data == '}')
|
||||
{
|
||||
(*data)++;
|
||||
return new JSONValue(object);
|
||||
}
|
||||
|
||||
// We want a string now...
|
||||
std::string name;
|
||||
if (!JSON::ExtractString(&(++(*data)), name))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// More whitespace?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Need a : now
|
||||
if (*((*data)++) != ':')
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// More whitespace?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The value is here
|
||||
JSONValue *value = Parse(data);
|
||||
if (value == NULL)
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add the name:value
|
||||
if (object.find(name) != object.end())
|
||||
delete object[name];
|
||||
object[name] = value;
|
||||
|
||||
// More whitespace?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// End of object?
|
||||
if (**data == '}')
|
||||
{
|
||||
(*data)++;
|
||||
return new JSONValue(object);
|
||||
}
|
||||
|
||||
// Want a , now
|
||||
if (**data != ',')
|
||||
{
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*data)++;
|
||||
}
|
||||
|
||||
// Only here if we ran out of data
|
||||
FREE_OBJECT(object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// An array?
|
||||
else if (**data == '[')
|
||||
{
|
||||
JSONArray array;
|
||||
|
||||
(*data)++;
|
||||
|
||||
while (**data != 0)
|
||||
{
|
||||
// Whitespace at the start?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Special case - empty array
|
||||
if (array.size() == 0 && **data == ']')
|
||||
{
|
||||
(*data)++;
|
||||
return new JSONValue(array);
|
||||
}
|
||||
|
||||
// Get the value
|
||||
JSONValue *value = Parse(data);
|
||||
if (value == NULL)
|
||||
{
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add the value
|
||||
array.push_back(value);
|
||||
|
||||
// More whitespace?
|
||||
if (!JSON::SkipWhitespace(data))
|
||||
{
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// End of array?
|
||||
if (**data == ']')
|
||||
{
|
||||
(*data)++;
|
||||
return new JSONValue(array);
|
||||
}
|
||||
|
||||
// Want a , now
|
||||
if (**data != ',')
|
||||
{
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*data)++;
|
||||
}
|
||||
|
||||
// Only here if we ran out of data
|
||||
FREE_ARRAY(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ran out of possibilites, it's bad!
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type NULL
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
JSONValue::JSONValue(/*NULL*/)
|
||||
{
|
||||
type = JSONType_Null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type String
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param char* m_char_value The string to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(const char *m_char_value)
|
||||
{
|
||||
type = JSONType_String;
|
||||
string_value = new std::string(std::string(m_char_value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type String
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param std::string m_string_value The string to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(const std::string &m_string_value)
|
||||
{
|
||||
type = JSONType_String;
|
||||
string_value = new std::string(m_string_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Bool
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param bool m_bool_value The bool to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(bool m_bool_value)
|
||||
{
|
||||
type = JSONType_Bool;
|
||||
bool_value = m_bool_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Number
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param double m_number_value The number to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(double m_number_value)
|
||||
{
|
||||
type = JSONType_Number;
|
||||
number_value = m_number_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Number
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param int m_integer_value The number to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(int m_integer_value)
|
||||
{
|
||||
type = JSONType_Number;
|
||||
number_value = (double) m_integer_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Array
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param JSONArray m_array_value The JSONArray to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(const JSONArray &m_array_value)
|
||||
{
|
||||
type = JSONType_Array;
|
||||
array_value = new JSONArray(m_array_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic constructor for creating a JSON Value of type Object
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param JSONObject m_object_value The JSONObject to use as the value
|
||||
*/
|
||||
JSONValue::JSONValue(const JSONObject &m_object_value)
|
||||
{
|
||||
type = JSONType_Object;
|
||||
object_value = new JSONObject(m_object_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor to perform a deep copy of array / object values
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param JSONValue m_source The source JSONValue that is being copied
|
||||
*/
|
||||
JSONValue::JSONValue(const JSONValue &m_source)
|
||||
{
|
||||
type = m_source.type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case JSONType_String:
|
||||
string_value = new std::string(*m_source.string_value);
|
||||
break;
|
||||
|
||||
case JSONType_Bool:
|
||||
bool_value = m_source.bool_value;
|
||||
break;
|
||||
|
||||
case JSONType_Number:
|
||||
number_value = m_source.number_value;
|
||||
break;
|
||||
|
||||
case JSONType_Array:
|
||||
{
|
||||
JSONArray source_array = *m_source.array_value;
|
||||
JSONArray::iterator iter;
|
||||
array_value = new JSONArray();
|
||||
for (iter = source_array.begin(); iter != source_array.end(); iter++)
|
||||
array_value->push_back(new JSONValue(**iter));
|
||||
break;
|
||||
}
|
||||
|
||||
case JSONType_Object:
|
||||
{
|
||||
JSONObject source_object = *m_source.object_value;
|
||||
object_value = new JSONObject();
|
||||
JSONObject::iterator iter;
|
||||
for (iter = source_object.begin(); iter != source_object.end(); iter++)
|
||||
{
|
||||
std::string name = (*iter).first;
|
||||
(*object_value)[name] = new JSONValue(*((*iter).second));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JSONType_Null:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The destructor for the JSON Value object
|
||||
* Handles deleting the objects in the array or the object value
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
JSONValue::~JSONValue()
|
||||
{
|
||||
if (type == JSONType_Array)
|
||||
{
|
||||
JSONArray::iterator iter;
|
||||
for (iter = array_value->begin(); iter != array_value->end(); iter++)
|
||||
delete *iter;
|
||||
delete array_value;
|
||||
}
|
||||
else if (type == JSONType_Object)
|
||||
{
|
||||
JSONObject::iterator iter;
|
||||
for (iter = object_value->begin(); iter != object_value->end(); iter++)
|
||||
{
|
||||
delete (*iter).second;
|
||||
}
|
||||
delete object_value;
|
||||
}
|
||||
else if (type == JSONType_String)
|
||||
{
|
||||
delete string_value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is a NULL
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is a NULL value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsNull() const
|
||||
{
|
||||
return type == JSONType_Null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is a String
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is a String value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsString() const
|
||||
{
|
||||
return type == JSONType_String;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is a Bool
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is a Bool value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsBool() const
|
||||
{
|
||||
return type == JSONType_Bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is a Number
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is a Number value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsNumber() const
|
||||
{
|
||||
return type == JSONType_Number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is an Array
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is an Array value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsArray() const
|
||||
{
|
||||
return type == JSONType_Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value is an Object
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if it is an Object value, false otherwise
|
||||
*/
|
||||
bool JSONValue::IsObject() const
|
||||
{
|
||||
return type == JSONType_Object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the String value of this JSONValue
|
||||
* Use IsString() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return std::string Returns the string value
|
||||
*/
|
||||
const std::string &JSONValue::AsString() const
|
||||
{
|
||||
return (*string_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Bool value of this JSONValue
|
||||
* Use IsBool() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns the bool value
|
||||
*/
|
||||
bool JSONValue::AsBool() const
|
||||
{
|
||||
return bool_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Number value of this JSONValue
|
||||
* Use IsNumber() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return double Returns the number value
|
||||
*/
|
||||
double JSONValue::AsNumber() const
|
||||
{
|
||||
return number_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Array value of this JSONValue
|
||||
* Use IsArray() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return JSONArray Returns the array value
|
||||
*/
|
||||
const JSONArray &JSONValue::AsArray() const
|
||||
{
|
||||
return (*array_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Object value of this JSONValue
|
||||
* Use IsObject() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return JSONObject Returns the object value
|
||||
*/
|
||||
const JSONObject &JSONValue::AsObject() const
|
||||
{
|
||||
return (*object_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of children of this JSONValue.
|
||||
* This number will be 0 or the actual number of children
|
||||
* if IsArray() or IsObject().
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return The number of children.
|
||||
*/
|
||||
std::size_t JSONValue::CountChildren() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case JSONType_Array:
|
||||
return array_value->size();
|
||||
case JSONType_Object:
|
||||
return object_value->size();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this JSONValue has a child at the given index.
|
||||
* Use IsArray() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if the array has a value at the given index.
|
||||
*/
|
||||
bool JSONValue::HasChild(std::size_t index) const
|
||||
{
|
||||
if (type == JSONType_Array)
|
||||
{
|
||||
return index < array_value->size();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the child of this JSONValue at the given index.
|
||||
* Use IsArray() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return JSONValue* Returns JSONValue at the given index or NULL
|
||||
* if it doesn't exist.
|
||||
*/
|
||||
JSONValue *JSONValue::Child(std::size_t index)
|
||||
{
|
||||
if (index < array_value->size())
|
||||
{
|
||||
return (*array_value)[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this JSONValue has a child at the given key.
|
||||
* Use IsObject() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool Returns true if the object has a value at the given key.
|
||||
*/
|
||||
bool JSONValue::HasChild(const char* name) const
|
||||
{
|
||||
if (type == JSONType_Object)
|
||||
{
|
||||
return object_value->find(name) != object_value->end();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the child of this JSONValue at the given key.
|
||||
* Use IsObject() before using this method.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return JSONValue* Returns JSONValue for the given key in the object
|
||||
* or NULL if it doesn't exist.
|
||||
*/
|
||||
JSONValue* JSONValue::Child(const char* name)
|
||||
{
|
||||
JSONObject::const_iterator it = object_value->find(name);
|
||||
if (it != object_value->end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the keys of the JSON Object or an empty vector
|
||||
* if this value is not an object.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return std::vector<std::string> A vector containing the keys.
|
||||
*/
|
||||
std::vector<std::string> JSONValue::ObjectKeys() const
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
|
||||
if (type == JSONType_Object)
|
||||
{
|
||||
JSONObject::const_iterator iter = object_value->begin();
|
||||
while (iter != object_value->end())
|
||||
{
|
||||
keys.push_back(iter->first);
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON encoded string for the value with all necessary characters escaped
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param bool prettyprint Enable prettyprint
|
||||
*
|
||||
* @return std::string Returns the JSON string
|
||||
*/
|
||||
std::string JSONValue::Stringify(bool const prettyprint) const
|
||||
{
|
||||
size_t const indentDepth = prettyprint ? 1 : 0;
|
||||
return StringifyImpl(indentDepth);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a JSON encoded string for the value with all necessary characters escaped
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param size_t indentDepth The prettyprint indentation depth (0 : no prettyprint)
|
||||
*
|
||||
* @return std::string Returns the JSON string
|
||||
*/
|
||||
std::string JSONValue::StringifyImpl(size_t const indentDepth) const
|
||||
{
|
||||
std::string ret_string;
|
||||
size_t const indentDepth1 = indentDepth ? indentDepth + 1 : 0;
|
||||
std::string const indentStr = Indent(indentDepth);
|
||||
std::string const indentStr1 = Indent(indentDepth1);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case JSONType_Null:
|
||||
ret_string = "null";
|
||||
break;
|
||||
|
||||
case JSONType_String:
|
||||
ret_string = StringifyString(*string_value);
|
||||
break;
|
||||
|
||||
case JSONType_Bool:
|
||||
ret_string = bool_value ? "true" : "false";
|
||||
break;
|
||||
|
||||
case JSONType_Number:
|
||||
{
|
||||
if (isinf(number_value) || isnan(number_value))
|
||||
ret_string = "null";
|
||||
else
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss.precision(15);
|
||||
ss << number_value;
|
||||
ret_string = ss.str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JSONType_Array:
|
||||
{
|
||||
ret_string = indentDepth ? "[\n" + indentStr1 : "[";
|
||||
JSONArray::const_iterator iter = array_value->begin();
|
||||
while (iter != array_value->end())
|
||||
{
|
||||
ret_string += (*iter)->StringifyImpl(indentDepth1);
|
||||
|
||||
// Not at the end - add a separator
|
||||
if (++iter != array_value->end())
|
||||
ret_string += ",";
|
||||
}
|
||||
ret_string += indentDepth ? "\n" + indentStr + "]" : "]";
|
||||
break;
|
||||
}
|
||||
|
||||
case JSONType_Object:
|
||||
{
|
||||
ret_string = indentDepth ? "{\n" + indentStr1 : "{";
|
||||
JSONObject::const_iterator iter = object_value->begin();
|
||||
while (iter != object_value->end())
|
||||
{
|
||||
ret_string += StringifyString((*iter).first);
|
||||
ret_string += ":";
|
||||
ret_string += (*iter).second->StringifyImpl(indentDepth1);
|
||||
|
||||
// Not at the end - add a separator
|
||||
if (++iter != object_value->end())
|
||||
ret_string += ",";
|
||||
}
|
||||
ret_string += indentDepth ? "\n" + indentStr + "}" : "}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON encoded string with all required fields escaped
|
||||
* Works from http://www.ecma-internationl.org/publications/files/ECMA-ST/ECMA-262.pdf
|
||||
* Section 15.12.3.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param std::string str The string that needs to have the characters escaped
|
||||
*
|
||||
* @return std::string Returns the JSON string
|
||||
*/
|
||||
std::string JSONValue::StringifyString(const std::string &str)
|
||||
{
|
||||
std::string str_out = "\"";
|
||||
|
||||
std::string::const_iterator iter = str.begin();
|
||||
while (iter != str.end())
|
||||
{
|
||||
char chr = *iter;
|
||||
|
||||
if (chr == '"' || chr == '\\' || chr == '/')
|
||||
{
|
||||
str_out += '\\';
|
||||
str_out += chr;
|
||||
}
|
||||
else if (chr == '\b')
|
||||
{
|
||||
str_out += "\\b";
|
||||
}
|
||||
else if (chr == '\f')
|
||||
{
|
||||
str_out += "\\f";
|
||||
}
|
||||
else if (chr == '\n')
|
||||
{
|
||||
str_out += "\\n";
|
||||
}
|
||||
else if (chr == '\r')
|
||||
{
|
||||
str_out += "\\r";
|
||||
}
|
||||
else if (chr == '\t')
|
||||
{
|
||||
str_out += "\\t";
|
||||
}
|
||||
else if (chr < ' ' || chr > 126)
|
||||
{
|
||||
str_out += "\\u";
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int value = (chr >> 12) & 0xf;
|
||||
if (value >= 0 && value <= 9)
|
||||
str_out += (char)('0' + value);
|
||||
else if (value >= 10 && value <= 15)
|
||||
str_out += (char)('A' + (value - 10));
|
||||
chr <<= 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str_out += chr;
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
str_out += "\"";
|
||||
return str_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the indentation string for the depth given
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param size_t indent The prettyprint indentation depth (0 : no indentation)
|
||||
*
|
||||
* @return std::string Returns the string
|
||||
*/
|
||||
std::string JSONValue::Indent(size_t depth)
|
||||
{
|
||||
const size_t indent_step = 2;
|
||||
depth ? --depth : 0;
|
||||
std::string indentStr(depth * indent_step, ' ');
|
||||
return indentStr;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* File JSONValue.h part of the SimpleJSON Library - http://mjpa.in/json
|
||||
*
|
||||
* Copyright (C) 2010 Mike Anchor
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _JSONVALUE_H_
|
||||
#define _JSONVALUE_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "JSON.h"
|
||||
|
||||
class JSON;
|
||||
|
||||
enum JSONType { JSONType_Null, JSONType_String, JSONType_Bool, JSONType_Number, JSONType_Array, JSONType_Object };
|
||||
|
||||
class JSONValue
|
||||
{
|
||||
friend class JSON;
|
||||
|
||||
public:
|
||||
JSONValue(/*NULL*/);
|
||||
JSONValue(const char *m_char_value);
|
||||
JSONValue(const std::string &m_string_value);
|
||||
JSONValue(bool m_bool_value);
|
||||
JSONValue(double m_number_value);
|
||||
JSONValue(int m_integer_value);
|
||||
JSONValue(const JSONArray &m_array_value);
|
||||
JSONValue(const JSONObject &m_object_value);
|
||||
JSONValue(const JSONValue &m_source);
|
||||
~JSONValue();
|
||||
|
||||
bool IsNull() const;
|
||||
bool IsString() const;
|
||||
bool IsBool() const;
|
||||
bool IsNumber() const;
|
||||
bool IsArray() const;
|
||||
bool IsObject() const;
|
||||
|
||||
const std::string &AsString() const;
|
||||
bool AsBool() const;
|
||||
double AsNumber() const;
|
||||
const JSONArray &AsArray() const;
|
||||
const JSONObject &AsObject() const;
|
||||
|
||||
std::size_t CountChildren() const;
|
||||
bool HasChild(std::size_t index) const;
|
||||
JSONValue *Child(std::size_t index);
|
||||
bool HasChild(const char* name) const;
|
||||
JSONValue *Child(const char* name);
|
||||
std::vector<std::string> ObjectKeys() const;
|
||||
|
||||
std::string Stringify(bool const prettyprint = false) const;
|
||||
protected:
|
||||
static JSONValue *Parse(const char **data);
|
||||
|
||||
private:
|
||||
static std::string StringifyString(const std::string &str);
|
||||
std::string StringifyImpl(size_t const indentDepth) const;
|
||||
static std::string Indent(size_t depth);
|
||||
|
||||
JSONType type;
|
||||
|
||||
union
|
||||
{
|
||||
bool bool_value;
|
||||
double number_value;
|
||||
std::string *string_value;
|
||||
JSONArray *array_value;
|
||||
JSONObject *object_value;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
+71
-87
@@ -12,7 +12,7 @@
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <json11.hpp>
|
||||
#include "mqtt/JSON.h"
|
||||
|
||||
MQTT *mqtt;
|
||||
|
||||
@@ -32,19 +32,19 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
|
||||
|
||||
if (moduleConfig.mqtt.json_enabled && (strncmp(topic, jsonTopic.c_str(), jsonTopic.length()) == 0)) {
|
||||
// check if this is a json payload message by comparing the topic start
|
||||
using namespace json11;
|
||||
char payloadStr[length + 1];
|
||||
memcpy(payloadStr, payload, length);
|
||||
payloadStr[length] = 0; // null terminated string
|
||||
std::string err;
|
||||
auto json = Json::parse(payloadStr, err);
|
||||
if (err.empty()) {
|
||||
JSONValue *json_value = JSON::Parse(payloadStr);
|
||||
if (json_value != NULL) {
|
||||
DEBUG_MSG("JSON Received on MQTT, parsing..\n");
|
||||
// check if it is a valid envelope
|
||||
if (json.object_items().count("sender") != 0 && json.object_items().count("payload") != 0 && json["type"].string_value().compare("sendtext") == 0) {
|
||||
JSONObject json;
|
||||
json = json_value->AsObject();
|
||||
if ((json.find("sender") != json.end()) && (json.find("payload") != json.end()) && (json.find("type") != json.end()) && json["type"]->IsString() && (json["type"]->AsString().compare("sendtext") == 0)) {
|
||||
// this is a valid envelope
|
||||
if (json["sender"].string_value().compare(owner.id) != 0) {
|
||||
std::string jsonPayloadStr = json["payload"].dump();
|
||||
if (json["payload"]->IsString() && json["type"]->IsString() && (json["sender"]->AsString().compare(owner.id) != 0)) {
|
||||
std::string jsonPayloadStr = json["payload"]->AsString();
|
||||
DEBUG_MSG("JSON payload %s, length %u\n", jsonPayloadStr.c_str(), jsonPayloadStr.length());
|
||||
|
||||
// construct protobuf data packet using TEXT_MESSAGE, send it to the mesh
|
||||
@@ -68,6 +68,7 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
|
||||
// no json, this is an invalid payload
|
||||
DEBUG_MSG("Invalid MQTT service envelope, topic %s, len %u!\n", topic, length);
|
||||
}
|
||||
delete json_value;
|
||||
} else {
|
||||
if (!pb_decode_from_bytes(payload, length, ServiceEnvelope_fields, &e)) {
|
||||
DEBUG_MSG("Invalid MQTT service envelope, topic %s, len %u!\n", topic, length);
|
||||
@@ -118,24 +119,16 @@ bool MQTT::connected()
|
||||
void MQTT::reconnect()
|
||||
{
|
||||
if (wantsLink()) {
|
||||
const char *serverAddr = "mqtt.meshtastic.org"; // default hostname
|
||||
int serverPort = 1883; // default server port
|
||||
const char *mqttUsername = "meshdev";
|
||||
const char *mqttPassword = "large4cats";
|
||||
// Defaults
|
||||
int serverPort = 1883;
|
||||
const char *serverAddr = default_mqtt_address;
|
||||
const char *mqttUsername = default_mqtt_username;
|
||||
const char *mqttPassword = default_mqtt_password;
|
||||
|
||||
if (*moduleConfig.mqtt.address) {
|
||||
serverAddr = moduleConfig.mqtt.address; // Override the default
|
||||
mqttUsername =
|
||||
moduleConfig.mqtt.username; // do not use the hardcoded credentials for a custom mqtt server
|
||||
serverAddr = moduleConfig.mqtt.address;
|
||||
mqttUsername = moduleConfig.mqtt.username;
|
||||
mqttPassword = moduleConfig.mqtt.password;
|
||||
} else {
|
||||
// we are using the default server. Use the hardcoded credentials by default, but allow overriding
|
||||
if (*moduleConfig.mqtt.username && moduleConfig.mqtt.username[0] != '\0') {
|
||||
mqttUsername = moduleConfig.mqtt.username;
|
||||
}
|
||||
if (*moduleConfig.mqtt.password && moduleConfig.mqtt.password[0] != '\0') {
|
||||
mqttPassword = moduleConfig.mqtt.password;
|
||||
}
|
||||
}
|
||||
|
||||
String server = String(serverAddr);
|
||||
@@ -148,8 +141,7 @@ void MQTT::reconnect()
|
||||
}
|
||||
pubSub.setServer(serverAddr, serverPort);
|
||||
|
||||
DEBUG_MSG("Connecting to MQTT server %s, port: %d, username: %s, password: %s\n", serverAddr, serverPort, mqttUsername,
|
||||
mqttPassword);
|
||||
DEBUG_MSG("Connecting to MQTT server %s, port: %d, username: %s, password: %s\n", serverAddr, serverPort, mqttUsername, mqttPassword);
|
||||
auto myStatus = (statusTopic + owner.id);
|
||||
bool connected = pubSub.connect(owner.id, mqttUsername, mqttPassword, myStatus.c_str(), 1, true, "offline");
|
||||
if (connected) {
|
||||
@@ -176,9 +168,11 @@ void MQTT::sendSubscriptions()
|
||||
String topic = cryptTopic + channels.getGlobalId(i) + "/#";
|
||||
DEBUG_MSG("Subscribing to %s\n", topic.c_str());
|
||||
pubSub.subscribe(topic.c_str(), 1); // FIXME, is QOS 1 right?
|
||||
String topicDecoded = jsonTopic + channels.getGlobalId(i) + "/#";
|
||||
DEBUG_MSG("Subscribing to %s\n", topicDecoded.c_str());
|
||||
pubSub.subscribe(topicDecoded.c_str(), 1); // FIXME, is QOS 1 right?
|
||||
if (moduleConfig.mqtt.json_enabled == true) {
|
||||
String topicDecoded = jsonTopic + channels.getGlobalId(i) + "/#";
|
||||
DEBUG_MSG("Subscribing to %s\n", topicDecoded.c_str());
|
||||
pubSub.subscribe(topicDecoded.c_str(), 1); // FIXME, is QOS 1 right?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,7 +251,6 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex)
|
||||
|
||||
if (moduleConfig.mqtt.json_enabled) {
|
||||
// handle json topic
|
||||
using namespace json11;
|
||||
auto jsonString = this->downstreamPacketToJson((MeshPacket *)&mp);
|
||||
if (jsonString.length() != 0) {
|
||||
String topicJson = jsonTopic + channelId + "/" + owner.id;
|
||||
@@ -271,12 +264,11 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex)
|
||||
// converts a downstream packet into a json message
|
||||
std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
||||
{
|
||||
using namespace json11;
|
||||
|
||||
// the created jsonObj is immutable after creation, so
|
||||
// we need to do the heavy lifting before assembling it.
|
||||
String msgType;
|
||||
Json msgPayload;
|
||||
JSONObject msgPayload;
|
||||
JSONObject jsonObj;
|
||||
|
||||
switch (mp->decoded.portnum) {
|
||||
case PortNum_TEXT_MESSAGE_APP: {
|
||||
@@ -287,17 +279,17 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
||||
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
|
||||
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
|
||||
// check if this is a JSON payload
|
||||
std::string err;
|
||||
auto json = Json::parse(payloadStr, err);
|
||||
if (err.empty()) {
|
||||
JSONValue *json_value = JSON::Parse(payloadStr);
|
||||
if (json_value != NULL) {
|
||||
DEBUG_MSG("text message payload is of type json\n");
|
||||
// if it is, then we can just use the json object
|
||||
msgPayload = json;
|
||||
jsonObj["payload"] = json_value;
|
||||
} else {
|
||||
// if it isn't, then we need to create a json object
|
||||
// with the string as the value
|
||||
DEBUG_MSG("text message payload is of type plaintext\n");
|
||||
msgPayload = Json::object{{"text", payloadStr}};
|
||||
msgPayload["text"] = new JSONValue(payloadStr);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -310,22 +302,19 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
if (decoded->which_variant == Telemetry_device_metrics_tag) {
|
||||
msgPayload = Json::object{
|
||||
{"battery_level", (int)decoded->variant.device_metrics.battery_level},
|
||||
{"voltage", decoded->variant.device_metrics.voltage},
|
||||
{"channel_utilization", decoded->variant.device_metrics.channel_utilization},
|
||||
{"air_util_tx", decoded->variant.device_metrics.air_util_tx},
|
||||
};
|
||||
msgPayload["battery_level"] = new JSONValue((int)decoded->variant.device_metrics.battery_level);
|
||||
msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage);
|
||||
msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization);
|
||||
msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx);
|
||||
} else if (decoded->which_variant == Telemetry_environment_metrics_tag) {
|
||||
msgPayload = Json::object{
|
||||
{"temperature", decoded->variant.environment_metrics.temperature},
|
||||
{"relative_humidity", decoded->variant.environment_metrics.relative_humidity},
|
||||
{"barometric_pressure", decoded->variant.environment_metrics.barometric_pressure},
|
||||
{"gas_resistance", decoded->variant.environment_metrics.gas_resistance},
|
||||
{"voltage", decoded->variant.environment_metrics.voltage},
|
||||
{"current", decoded->variant.environment_metrics.current},
|
||||
};
|
||||
msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature);
|
||||
msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity);
|
||||
msgPayload["barometric_pressure"] = new JSONValue(decoded->variant.environment_metrics.barometric_pressure);
|
||||
msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance);
|
||||
msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage);
|
||||
msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current);
|
||||
}
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else
|
||||
DEBUG_MSG("Error decoding protobuf for telemetry message!\n");
|
||||
};
|
||||
@@ -339,13 +328,11 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &User_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload = Json::object{
|
||||
{"id", decoded->id},
|
||||
{"longname", decoded->long_name},
|
||||
{"shortname", decoded->short_name},
|
||||
{"hardware", decoded->hw_model}
|
||||
};
|
||||
|
||||
msgPayload["id"] = new JSONValue(decoded->id);
|
||||
msgPayload["longname"] = new JSONValue(decoded->long_name);
|
||||
msgPayload["shortname"] = new JSONValue(decoded->short_name);
|
||||
msgPayload["hardware"] = new JSONValue(decoded->hw_model);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else
|
||||
DEBUG_MSG("Error decoding protobuf for nodeinfo message!\n");
|
||||
};
|
||||
@@ -359,13 +346,12 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Position_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload = Json::object{
|
||||
{"time", (int)decoded->time},
|
||||
{"pos_timestamp", (int)decoded->timestamp},
|
||||
{"latitude_i", (int)decoded->latitude_i},
|
||||
{"longitude_i", (int)decoded->longitude_i},
|
||||
{"altitude", (int)decoded->altitude}
|
||||
};
|
||||
msgPayload["time"] = new JSONValue((int)decoded->time);
|
||||
msgPayload["timestamp"] = new JSONValue((int)decoded->timestamp);
|
||||
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
|
||||
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
|
||||
msgPayload["altitude"] = new JSONValue((int)decoded->altitude);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else {
|
||||
DEBUG_MSG("Error decoding protobuf for position message!\n");
|
||||
}
|
||||
@@ -381,15 +367,14 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Waypoint_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
msgPayload = Json::object{
|
||||
{"id", (int)decoded->id},
|
||||
{"name", decoded->name},
|
||||
{"description", decoded->description},
|
||||
{"expire", (int)decoded->expire},
|
||||
{"locked", decoded->locked},
|
||||
{"latitude_i", (int)decoded->latitude_i},
|
||||
{"longitude_i", (int)decoded->longitude_i},
|
||||
};
|
||||
msgPayload["id"] = new JSONValue((int)decoded->id);
|
||||
msgPayload["name"] = new JSONValue(decoded->name);
|
||||
msgPayload["description"] = new JSONValue(decoded->description);
|
||||
msgPayload["expire"] = new JSONValue((int)decoded->expire);
|
||||
msgPayload["locked"] = new JSONValue(decoded->locked);
|
||||
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
|
||||
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
|
||||
jsonObj["payload"] = new JSONValue(msgPayload);
|
||||
} else {
|
||||
DEBUG_MSG("Error decoding protobuf for position message!\n");
|
||||
}
|
||||
@@ -401,21 +386,20 @@ std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
|
||||
break;
|
||||
}
|
||||
|
||||
// assemble the final jsonObj
|
||||
Json jsonObj = Json::object{
|
||||
{"id", Json((int)mp->id)},
|
||||
{"timestamp", Json((int)mp->rx_time)},
|
||||
{"to", Json((int)mp->to)},
|
||||
{"from", Json((int)mp->from)},
|
||||
{"channel", Json((int)mp->channel)},
|
||||
{"type", msgType.c_str()},
|
||||
{"sender", owner.id},
|
||||
{"payload", msgPayload}
|
||||
};
|
||||
jsonObj["id"] = new JSONValue((int)mp->id);
|
||||
jsonObj["timestamp"] = new JSONValue((int)mp->rx_time);
|
||||
jsonObj["to"] = new JSONValue((int)mp->to);
|
||||
jsonObj["from"] = new JSONValue((int)mp->from);
|
||||
jsonObj["channel"] = new JSONValue((int)mp->channel);
|
||||
jsonObj["type"] = new JSONValue(msgType.c_str());
|
||||
jsonObj["sender"] = new JSONValue(owner.id);
|
||||
|
||||
// serialize and write it to the stream
|
||||
JSONValue *value = new JSONValue(jsonObj);
|
||||
std::string jsonStr = value->Stringify();
|
||||
|
||||
// serialize and return it
|
||||
std::string jsonStr = jsonObj.dump();
|
||||
DEBUG_MSG("serialized json message: %s\n", jsonStr.c_str());
|
||||
|
||||
delete value;
|
||||
return jsonStr;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,10 @@
|
||||
#define HW_VENDOR HardwareModel_STATION_G1
|
||||
#elif defined(DR_DEV)
|
||||
#define HW_VENDOR HardwareModel_DR_DEV
|
||||
#elif defined(HELTEC_V3)
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V3
|
||||
#elif defined(HELTEC_WSL_V3)
|
||||
#define HW_VENDOR HardwareModel_HELTEC_WSL_V3
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <driver/rtc_io.h>
|
||||
#include <nvs.h>
|
||||
#include <nvs_flash.h>
|
||||
#include "soc/rtc.h"
|
||||
|
||||
NimbleBluetooth *nimbleBluetooth;
|
||||
|
||||
@@ -23,7 +24,7 @@ void getMacAddr(uint8_t *dmac)
|
||||
}
|
||||
|
||||
void setBluetoothEnable(bool on) {
|
||||
|
||||
|
||||
if (!isWifiAvailable() && config.bluetooth.enabled == true) {
|
||||
if (!nimbleBluetooth) {
|
||||
nimbleBluetooth = new NimbleBluetooth();
|
||||
@@ -36,6 +37,44 @@ void setBluetoothEnable(bool on) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_32768HZ
|
||||
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
|
||||
|
||||
static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
|
||||
{
|
||||
const uint32_t cal_count = 1000;
|
||||
// const float factor = (1 << 19) * 1000.0f; unused var?
|
||||
uint32_t cali_val;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
cali_val = rtc_clk_cal(cal_clk, cal_count);
|
||||
}
|
||||
return cali_val;
|
||||
}
|
||||
|
||||
void enableSlowCLK()
|
||||
{
|
||||
rtc_clk_32k_enable(true);
|
||||
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);
|
||||
|
||||
if (cal_32k == 0) {
|
||||
DEBUG_MSG("32K XTAL OSC has not started up\n");
|
||||
} else {
|
||||
rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
|
||||
DEBUG_MSG("Switching RTC Source to 32.768Khz succeeded, using 32K XTAL\n");
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
CALIBRATE_ONE(RTC_CAL_32K_XTAL);
|
||||
}
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
CALIBRATE_ONE(RTC_CAL_32K_XTAL);
|
||||
if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
|
||||
DEBUG_MSG("Warning: Failed to switch 32K XTAL RTC source to 32.768Khz !!! \n"); return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void esp32Setup()
|
||||
{
|
||||
uint32_t seed = esp_random();
|
||||
@@ -83,6 +122,10 @@ void esp32Setup()
|
||||
|
||||
res = esp_task_wdt_add(NULL);
|
||||
assert(res == ESP_OK);
|
||||
|
||||
#ifdef HAS_32768HZ
|
||||
enableSlowCLK();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
@@ -36,7 +36,10 @@ cstyleCast
|
||||
// ignore stuff that is not ours
|
||||
*:.pio/*
|
||||
*:*/libdeps/*
|
||||
noExplicitConstructor:*/mqtt/*
|
||||
postfixOperator:*/mqtt/*
|
||||
|
||||
// these two caused issues
|
||||
missingOverride
|
||||
virtualCallInConstructor
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
[env:heltec-v3]
|
||||
platform = https://github.com/Baptou88/platform-espressif32.git
|
||||
extends = esp32_base
|
||||
board = heltec_wifi_lora_32_V3
|
||||
# Temporary: https://community.platformio.org/t/heltec-esp32-lora-v3-board-support/30406/2
|
||||
platform_packages =
|
||||
framework-arduinoespressif32@https://github.com/Baptou88/arduino-esp32.git
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/heltec_v3
|
||||
@@ -0,0 +1,32 @@
|
||||
#define LED_PIN LED
|
||||
|
||||
#define HAS_GPS 0
|
||||
|
||||
#define RESET_OLED RST_OLED
|
||||
#define I2C_SDA SDA_OLED // I2C pins for this board
|
||||
#define I2C_SCL SCL_OLED
|
||||
|
||||
#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
|
||||
#define BUTTON_PIN 0
|
||||
|
||||
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
#define ADC_MULTIPLIER 5.22
|
||||
|
||||
#define USE_SX1262
|
||||
|
||||
#define LORA_DIO0 -1 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 12
|
||||
#define LORA_DIO1 14 // SX1262 IRQ
|
||||
#define LORA_DIO2 13 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK 9
|
||||
#define RF95_MISO 11
|
||||
#define RF95_MOSI 10
|
||||
#define RF95_NSS 8
|
||||
|
||||
#define SX126X_CS RF95_NSS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_E22
|
||||
@@ -0,0 +1,9 @@
|
||||
[env:heltec-wsl-v3]
|
||||
platform = https://github.com/Baptou88/platform-espressif32.git
|
||||
extends = esp32_base
|
||||
board = heltec_wifi_lora_32_V3
|
||||
# Temporary: https://community.platformio.org/t/heltec-esp32-lora-v3-board-support/30406/2
|
||||
platform_packages =
|
||||
framework-arduinoespressif32@https://github.com/Baptou88/arduino-esp32.git
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/heltec_wsl_v3
|
||||
@@ -0,0 +1,29 @@
|
||||
#define LED_PIN LED
|
||||
|
||||
#define HAS_SCREEN 0
|
||||
#define HAS_GPS 0
|
||||
|
||||
#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
|
||||
#define BUTTON_PIN 0
|
||||
|
||||
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
#define ADC_MULTIPLIER 5.22
|
||||
|
||||
#define USE_SX1262
|
||||
|
||||
#define LORA_DIO0 -1 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 12
|
||||
#define LORA_DIO1 14 // SX1262 IRQ
|
||||
#define LORA_DIO2 13 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK 9
|
||||
#define RF95_MISO 11
|
||||
#define RF95_MOSI 10
|
||||
#define RF95_NSS 8
|
||||
|
||||
#define SX126X_CS RF95_NSS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_E22
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "Speaker.h"
|
||||
|
||||
TONE::TONE(void) {
|
||||
_volume = 5;
|
||||
_begun = false;
|
||||
}
|
||||
|
||||
void TONE::begin() {
|
||||
_begun = true;
|
||||
ledcSetup(TONE_PIN_CHANNEL, 0, 13);
|
||||
ledcAttachPin(PIN_BUZZER, TONE_PIN_CHANNEL);
|
||||
}
|
||||
|
||||
void TONE::end() {
|
||||
mute();
|
||||
ledcDetachPin(PIN_BUZZER);
|
||||
_begun = false;
|
||||
}
|
||||
|
||||
void TONE::tone(uint16_t frequency) {
|
||||
if(!_begun) begin();
|
||||
ledcWriteTone(TONE_PIN_CHANNEL, frequency);
|
||||
ledcWrite(TONE_PIN_CHANNEL, 0x400 >> _volume);
|
||||
}
|
||||
|
||||
void TONE::setVolume(uint8_t volume) {
|
||||
_volume = 11 - volume;
|
||||
}
|
||||
|
||||
void TONE::mute() {
|
||||
ledcWriteTone(TONE_PIN_CHANNEL, 0);
|
||||
digitalWrite(PIN_BUZZER, 0);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef _SPEAKER_H_
|
||||
#define _SPEAKER_H_
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
#include "esp32-hal-dac.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
class TONE {
|
||||
public:
|
||||
TONE(void);
|
||||
|
||||
void begin();
|
||||
void end();
|
||||
void mute();
|
||||
void tone(uint16_t frequency);
|
||||
void setVolume(uint8_t volume);
|
||||
|
||||
private:
|
||||
uint8_t _volume;
|
||||
bool _begun;
|
||||
bool speaker_on;
|
||||
};
|
||||
#endif
|
||||
@@ -6,7 +6,6 @@ monitor_port = COM8
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_src_filter =
|
||||
${esp32_base.build_src_filter}
|
||||
+<../variants/m5stack_core>
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -I variants/m5stack_core
|
||||
-DILI9341_DRIVER
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#define BUTTON_PIN 38
|
||||
|
||||
#define PIN_BUZZER 25
|
||||
#define TONE_PIN_CHANNEL 0
|
||||
|
||||
#undef RF95_SCK
|
||||
#undef RF95_MISO
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
[env:m5stack-coreink]
|
||||
extends = esp32_base
|
||||
board = m5stack-coreink
|
||||
build_src_filter =
|
||||
${esp32_base.build_src_filter}
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D M5_COREINK -I variants/m5stack_coreink
|
||||
${esp32_base.build_flags} -I variants/m5stack_coreink
|
||||
;-D RADIOLIB_VERBOSE
|
||||
-Ofast
|
||||
-D__MCUXPRESSO
|
||||
-DEPD_HEIGHT=200
|
||||
-DEPD_WIDTH=200
|
||||
-DUSER_SETUP_LOADED
|
||||
-DM5_COREINK
|
||||
-DM5STACK
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
zinggjm/GxEPD2@^1.4.9
|
||||
lewisxhe/PCF8563_Library@^1.0.1
|
||||
lib_ignore =
|
||||
m5stack-coreink
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.f_cpu = 240000000L
|
||||
upload_protocol = esptool
|
||||
upload_port = /dev/ttyACM*
|
||||
upload_port = /dev/ttyACM0
|
||||
|
||||
@@ -1,34 +1,39 @@
|
||||
#define I2C_SDA 21 //-1
|
||||
#define I2C_SCL 22 //-1
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
|
||||
//#define LED_PIN 10
|
||||
// LED?
|
||||
#define LED_INVERTED 0
|
||||
#define LED_PIN 10
|
||||
|
||||
#include "pcf8563.h"
|
||||
// PCF8563 RTC Module
|
||||
#define PCF8563_RTC 0x51
|
||||
|
||||
#define BUTTON_NEED_PULLUP
|
||||
#define BUTTON_PIN 5
|
||||
#define HAS_RTC 1
|
||||
|
||||
//Wheel
|
||||
// Down 37
|
||||
// Push 38
|
||||
// Up 39
|
||||
|
||||
// Top Physical Button 5
|
||||
|
||||
#define BUTTON_NEED_PULLUP
|
||||
#define BUTTON_PIN 5
|
||||
|
||||
//BUZZER
|
||||
#define PIN_BUZZER 2
|
||||
|
||||
#undef RF95_SCK
|
||||
#undef RF95_MISO
|
||||
#undef RF95_MOSI
|
||||
#undef RF95_NSS
|
||||
#define USE_RF95
|
||||
|
||||
#define RF95_SCK 18 //13
|
||||
#define RF95_MISO 34 //26
|
||||
#define RF95_MOSI 23 //25
|
||||
#define RF95_SCK 18
|
||||
#define RF95_MISO 34
|
||||
#define RF95_MOSI 23
|
||||
#define RF95_NSS 14
|
||||
#define LORA_DIO0 25 //32 now moved from ext port
|
||||
#define LORA_RESET 26 //33 now moved from ext port
|
||||
#define LORA_DIO0 25
|
||||
#define LORA_RESET 26
|
||||
#define LORA_DIO1 RADIOLIB_NC
|
||||
#define LORA_DIO2 RADIOLIB_NC
|
||||
|
||||
@@ -39,12 +44,10 @@
|
||||
#define USE_EINK
|
||||
//https://docs.m5stack.com/en/core/coreink
|
||||
//https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/schematic/Core/coreink/coreink_sch.pdf
|
||||
#define PIN_EINK_EN -1
|
||||
#define PIN_EINK_CS 9 // EPD_CS
|
||||
#define PIN_EINK_BUSY 4 // EPD_BUSY
|
||||
#define PIN_EINK_EN -1 // N/C
|
||||
#define PIN_EINK_CS 9 // EPD_CS
|
||||
#define PIN_EINK_BUSY 4 // EPD_BUSY
|
||||
#define PIN_EINK_DC 15 // EPD_D/C
|
||||
#define PIN_EINK_RES -1 // Connected to GPIO0 but no needed !!!! maybe causing issue ?
|
||||
#define PIN_EINK_SCLK 18 // EPD_SCLK
|
||||
#define PIN_EINK_RES -1 // Connected but not needed
|
||||
#define PIN_EINK_SCLK 18 // EPD_SCLK
|
||||
#define PIN_EINK_MOSI 23 // EPD_MOSI
|
||||
|
||||
#define HAS_RTC 1
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
[env:native]
|
||||
platform = https://github.com/meshtastic/platform-native.git
|
||||
extends = portduino_base
|
||||
build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino
|
||||
framework = arduino
|
||||
board = cross_platform
|
||||
lib_deps = ${portduino_base.lib_deps}
|
||||
build_src_filter = ${portduino_base.build_src_filter}
|
||||
|
||||
; The Portduino based sim environment on top of a linux OS and touching linux hardware devices
|
||||
[env:linux]
|
||||
platform = https://github.com/meshtastic/platform-native.git
|
||||
extends = portduino_base
|
||||
build_flags = ${portduino_base.build_flags} -O0 -lgpiod -I variants/portduino
|
||||
framework = arduino
|
||||
board = linux_hardware
|
||||
lib_deps = ${portduino_base.lib_deps}
|
||||
build_src_filter = ${portduino_base.build_src_filter}
|
||||
|
||||
; The Portduino based sim environment on top of a linux OS and touching linux hardware devices
|
||||
[env:linux-arm]
|
||||
extends = portduino_base
|
||||
build_flags = ${portduino_base.build_flags} -O0 -lgpiod -I variants/portduino
|
||||
board = linux_arm
|
||||
lib_deps = ${portduino_base.lib_deps}
|
||||
build_src_filter = ${portduino_base.build_src_filter}
|
||||
|
||||
@@ -23,16 +23,3 @@
|
||||
// HOPE RFM90 does not have a TCXO therefore not SX126X_E22
|
||||
#endif
|
||||
|
||||
// Temporary shim for radio lib macros until we upgrade to upstream for portduino
|
||||
#define RADIOLIB_PREAMBLE_DETECTED PREAMBLE_DETECTED
|
||||
|
||||
#define RADIOLIB_ERR_NONE ERR_NONE
|
||||
#define RADIOLIB_ERR_WRONG_MODEM ERR_WRONG_MODEM
|
||||
|
||||
#define RADIOLIB_SX126X_IRQ_HEADER_VALID SX126X_IRQ_HEADER_VALID
|
||||
#define RADIOLIB_SX126X_LORA_CRC_ON SX126X_LORA_CRC_ON
|
||||
|
||||
#define RADIOLIB_SX127X_REG_TCXO SX127X_REG_TCXO
|
||||
#define RADIOLIB_SX127X_REG_MODEM_STAT SX127X_REG_MODEM_STAT
|
||||
#define RADIOLIB_SX127X_SYNC_WORD SX127X_SYNC_WORD
|
||||
#define RADIOLIB_SX127X_MASK_IRQ_FLAG_VALID_HEADER SX127X_MASK_IRQ_FLAG_VALID_HEADER
|
||||
|
||||
+10
-11
@@ -59,11 +59,11 @@ static const uint8_t SCK = 33;
|
||||
|
||||
// https://docs.rakwireless.com/Product-Categories/WisBlock/RAK13300/
|
||||
|
||||
#define LORA_DIO0 -1 // a No connect on the SX1262/SX1268 module
|
||||
#define LORA_RESET WB_IO4 // RST for SX1276, and for SX1262/SX1268
|
||||
#define LORA_DIO1 WB_IO6 // IRQ for SX1262/SX1268
|
||||
#define LORA_DIO2 WB_IO5 // BUSY for SX1262/SX1268
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262/SX1268, if DIO3 is high the TXCO is enabled
|
||||
#define LORA_DIO0 RADIOLIB_NC // a No connect on the SX1262/SX1268 module
|
||||
#define LORA_RESET WB_IO4 // RST for SX1276, and for SX1262/SX1268
|
||||
#define LORA_DIO1 WB_IO6 // IRQ for SX1262/SX1268
|
||||
#define LORA_DIO2 WB_IO5 // BUSY for SX1262/SX1268
|
||||
#define LORA_DIO3 RADIOLIB_NC // Not connected on PCB, but internally on the TTGO SX1262/SX1268, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#undef RF95_SCK
|
||||
#define RF95_SCK SCK
|
||||
@@ -75,10 +75,9 @@ static const uint8_t SCK = 33;
|
||||
#define RF95_NSS SS
|
||||
|
||||
#define USE_SX1262
|
||||
#define SX126X_CS (SS)// NSS for SX126X
|
||||
#define SX126X_DIO1 (LORA_DIO1)
|
||||
#define SX126X_BUSY (LORA_DIO2)
|
||||
#define SX126X_RESET (LORA_RESET)
|
||||
#define SX126X_TXEN (-1)
|
||||
#define SX126X_RXEN (WB_IO3)
|
||||
#define SX126X_CS SS// NSS for SX126X
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_POWER_EN WB_IO3
|
||||
#define SX126X_E22 // DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
|
||||
|
||||
@@ -8,7 +8,7 @@ lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
melopero/Melopero RV3028@^1.1.0
|
||||
https://github.com/meshtastic/RAK13800-W5100S.git#b680706eb8006cd62c919ac74c8af1950eb82c81
|
||||
https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2
|
||||
debug_tool = jlink
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
;upload_protocol = jlink
|
||||
@@ -205,7 +205,8 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
#define RV3028_RTC (uint8_t) 0b1010010
|
||||
|
||||
// RAK18001 Buzzer in Slot C
|
||||
#define PIN_BUZZER 21 // IO3 is PWM2
|
||||
// #define PIN_BUZZER 21 // IO3 is PWM2
|
||||
// NEW: set this via protobuf instead!
|
||||
|
||||
// Battery
|
||||
// The battery sense is hooked to pin A0 (5)
|
||||
|
||||
@@ -17,20 +17,28 @@
|
||||
static const uint8_t TX = 43;
|
||||
static const uint8_t RX = 44;
|
||||
|
||||
// The default Wire will be mapped to PMU and RTC
|
||||
static const uint8_t SDA = 42;
|
||||
static const uint8_t SCL = 41;
|
||||
|
||||
// Default SPI will be mapped to Radio
|
||||
static const uint8_t SS = 10;
|
||||
static const uint8_t MOSI = 11;
|
||||
static const uint8_t MISO = 13;
|
||||
static const uint8_t SCK = 12;
|
||||
|
||||
#define SDMMC_CMD (35)
|
||||
#define SDMMC_CLK (36)
|
||||
#define SDMMC_DATA (37)
|
||||
// Another SPI bus shares SD card and QMI8653 inertial measurement sensor
|
||||
#define SPI_MOSI (35)
|
||||
#define SPI_SCK (36)
|
||||
#define SPI_MISO (37)
|
||||
#define SPI_CS (47)
|
||||
#define IMU_CS (34)
|
||||
|
||||
#define ACCEL_INT1 (34)
|
||||
#define ACCEL_INT2 (33)
|
||||
#define SDCARD_CS SPI_CS
|
||||
#define IMU_INT (33)
|
||||
// #define PMU_IRQ (40)
|
||||
#define RTC_INT (14)
|
||||
|
||||
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
|
||||
|
||||
#define I2C_SDA1 42 //Used for PMU management
|
||||
#define I2C_SCL1 41 //Used for PMU management
|
||||
#define I2C_SDA1 42 //Used for PMU management and PCF8563
|
||||
#define I2C_SCL1 41 //Used for PMU management and PCF8563
|
||||
|
||||
#define I2C_SDA 17 //For sensors and screens
|
||||
#define I2C_SCL 18 //For sensors and screens
|
||||
#define I2C_SDA 17 //For QMC6310 sensors and screens
|
||||
#define I2C_SCL 18 //For QMC6310 sensors and screens
|
||||
|
||||
#define BUTTON_PIN 0 // The middle button GPIO on the T-Beam S3
|
||||
//#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed. Does anyone use this? It is not documented anywhere.
|
||||
// #define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Module.
|
||||
|
||||
#define BUTTON1_PIN 47 //Additional keys
|
||||
|
||||
|
||||
#define LED_INVERTED 1
|
||||
// #define LED_PIN 4 // Newer tbeams (1.1) have an extra led on GPIO4
|
||||
|
||||
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
|
||||
// not found then probe for SX1262
|
||||
@@ -42,8 +40,9 @@
|
||||
// #define PMU_IRQ 40
|
||||
#define HAS_AXP2101
|
||||
|
||||
// Specify the PMU as Wire1. In the t-beam-s3-core, the PMU enjoys a separate bus
|
||||
// Specify the PMU as Wire1. In the t-beam-s3 core, PCF8563 and PMU share the bus
|
||||
#define PMU_USE_WIRE1
|
||||
#define RTC_USE_WIRE1
|
||||
|
||||
#define RF95_SCK 12
|
||||
#define RF95_MISO 13
|
||||
@@ -56,10 +55,14 @@
|
||||
#define GPS_1PPS_PIN 6
|
||||
|
||||
|
||||
#define HAS_SDCARD //Have 3-bit SDMMC interface SD card slot
|
||||
#define HAS_SDCARD //Have SPI interface SD card slot
|
||||
#define SDCARD_USE_SPI1
|
||||
|
||||
// PCF8563 RTC Module
|
||||
// #define PCF8563_RTC 0x51 //Putting definitions in variant. h does not compile correctly
|
||||
|
||||
#define HAS_RTC 1
|
||||
|
||||
//has 32768 Hz crystal
|
||||
#define HAS_32768HZ
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
|
||||
// not found then probe for SX1262
|
||||
#define USE_RF95
|
||||
#define USE_RF95 // RFM95/SX127x
|
||||
#define USE_SX1262
|
||||
#define USE_SX1268
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
|
||||
|
||||
// #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 2 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
|
||||
#define BUTTON_NEED_PULLUP
|
||||
|
||||
@@ -5,4 +5,4 @@ lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
caveman99/ESP32 Codec2@^1.0.1
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V2_1_18 -I variants/tlora_v2_1_18
|
||||
${esp32_base.build_flags} -D TLORA_V2_1_18 -I variants/tlora_v2_1_18 -D RADIOLIB_GODMODE
|
||||
@@ -12,20 +12,17 @@
|
||||
#define I2C_SDA 21 // I2C pins for this board
|
||||
#define I2C_SCL 22
|
||||
|
||||
// #define RESET_OLED 16 // If defined, this pin will be used to reset the display controller. Crashes on newer ESP-IDF and not needed per schematic
|
||||
|
||||
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
|
||||
#define LED_PIN 25 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 12 // If defined, this will be used for user button presses,
|
||||
|
||||
#define BUTTON_NEED_PULLUP
|
||||
|
||||
#define USE_SX1280
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 23
|
||||
|
||||
#define SX128X_CS 18 // FIXME - we really should define LORA_CS instead
|
||||
#define SX128X_DIO1 33
|
||||
#define SX128X_DIO1 26
|
||||
#define SX128X_DIO2 33
|
||||
#define SX128X_BUSY 32
|
||||
#define SX128X_RESET LORA_RESET
|
||||
#define SX128X_E22 // Not really an E22 but TTGO seems to be trying to clone that
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 2
|
||||
minor = 0
|
||||
build = 2
|
||||
build = 6
|
||||
|
||||
Reference in New Issue
Block a user