Compare commits

...

123 Commits

Author SHA1 Message Date
mkinney
4df0e910b8 Update main_matrix.yml
add nano-g1
2022-04-27 10:23:20 -07:00
mkinney
3a5f492106 add nano_g1 to build (#1417) 2022-04-27 12:20:10 -05:00
Thomas Göttgens
2dbb9075a3 Merge pull request #1408 from Pedestrian11/patch-1
TTGO_T_ECHO to use batteries, PIN_EINK_PWR_ON must be set to high
2022-04-27 15:45:01 +02:00
Thomas Göttgens
e5715a0048 Merge branch 'master' into patch-1 2022-04-27 15:32:05 +02:00
Thomas Göttgens
629db8c718 Fix build errors and add a bit of failsafe 2022-04-27 15:30:27 +02:00
Ben Meadors
cc2a84afcd Bump version for release 2022-04-27 07:03:09 -05:00
Thomas Göttgens
6c1dc0d71a Merge pull request #1415 from meshtastic/RAK12002
I2C RTC Support (RAK12002)
2022-04-27 11:17:31 +02:00
Thomas Göttgens
9e97fac252 - implement generic support for on-device battery powered RTC Modules.
- implement support for I2C RV-3028 based RTC modules like the RAK12002
- pretty print some debug timestamps
2022-04-27 11:05:08 +02:00
Thomas Göttgens
3a9086dfc5 We may have RAK modules in Slot D pulling IO5 to Low permanently (like the RAK12002 RTC Module). React to assumed Long presses of the device button only 30 seconds after bootup to prevent a reboot loop. This is Particularly important for button-less RAK19003 Baseboard. 2022-04-27 11:02:45 +02:00
Thomas Göttgens
a0f34a8d0a Make Debug Log less spammy 2022-04-27 11:00:26 +02:00
Ben Meadors
359b41d869 Position fwd phone (#1413)
* Correct factory reset code for NRF (from 1.2)

* Changes from 1.2

* Update proto ref

* Whoops

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-04-26 19:40:24 -05:00
Thomas Göttgens
04723bd1a0 Merge pull request #1412 from meshtastic/nrf-softcrypt
use a tiny software AES lib if user wants AES-256
2022-04-26 21:45:54 +02:00
Thomas Göttgens
89d6990a92 Merge branch 'nrf-softcrypt' of github.com:meshtastic/Meshtastic-device into nrf-softcrypt 2022-04-26 21:30:21 +02:00
Thomas Göttgens
96f20287ff fix scope error 2022-04-26 21:30:14 +02:00
Thomas Göttgens
d8ba25747b Merge branch 'master' into nrf-softcrypt 2022-04-26 21:25:01 +02:00
Thomas Göttgens
e66c01f0e6 Merge branch 'nrf-softcrypt' of github.com:meshtastic/Meshtastic-device into nrf-softcrypt 2022-04-26 21:24:29 +02:00
Thomas Göttgens
aaea2e7456 make cppcheck happy 2022-04-26 21:24:21 +02:00
Ben Meadors
92185e763d Bump version for another 1.3 release 2022-04-26 14:10:17 -05:00
Thomas Göttgens
4de5944474 Merge branch 'master' into nrf-softcrypt 2022-04-26 17:52:33 +02:00
Thomas Göttgens
76e48178c8 use a tiny software AES lib if user needs AES-256 2022-04-26 17:50:50 +02:00
Ben Meadors
75e7bccdfb Fix assert execution halt in nrf devices (#1410) 2022-04-26 06:49:05 -05:00
Ben Meadors
3786b1ee15 Reboot implementation for nrf devices (#1411) 2022-04-26 06:48:26 -05:00
Thomas Göttgens
f2dec07c8d Merge pull request #1409 from meshtastic/gps-check
GPS Fixes
2022-04-26 13:17:04 +02:00
Thomas Göttgens
701707a01b - Bounds Check is working on big integers, don't throw away valid coordinates.
- Set ublox chips back to NMEA mode if they have been configured wrongly before.
2022-04-26 13:00:11 +02:00
Pedestrian
13fa7c1628 TTGO_T_ECHO to use batteries, PIN_EINK_PWR_ON must be set to high 2022-04-26 17:43:32 +08:00
Thomas Göttgens
d640478289 Merge pull request #1405 from meshtastic/rak-hw-crypto
use nRF52 Hardware Cryptography
2022-04-25 11:43:05 +02:00
Thomas Göttgens
b8b1a5cfb7 Merge branch 'master' into rak-hw-crypto 2022-04-25 11:14:04 +02:00
Thomas Göttgens
770f17f382 use nRF Hardware Cryptography. Removes the need for the sdk-nrfxlib submodule 2022-04-25 11:01:54 +02:00
Sacha Weatherstone
8ea3ebf74b Update README.md 2022-04-25 18:45:47 +10:00
Sacha Weatherstone
cbf238652e Update README.md 2022-04-25 16:51:39 +10:00
Thomas Göttgens
c17cd47689 Update main_matrix.yml (#1402) 2022-04-25 16:48:04 +10:00
Thomas Göttgens
d2c278a856 Update main_matrix.yml (#1401) 2022-04-25 16:24:08 +10:00
Thomas Göttgens
213d9512f1 WIP: unify the RAK targets into one firmware (#1350)
* First steps to unify GPS Lib for RAK 1910 and RAK 12500

* Technicalities. Out with the old and build the new.

* Adapt Matrix

* We use 0.4.5 now

* While we're at it, yank the RAK815, it's EOL

* Satisfy CI - for now

* - yank UBX library, talk to GPS chip with NMEA only.
- more autodetect going on, this time for the Eink Display.

TODO: actually do something with the scan findings.

* i swear this works on windows! :-)

* these are only there to make CI happy

* don't update eink display if not detected.

* Replace Oberon Crypt Library with modified Adafruit Library. This elimintaes the need for the sdk-nfxlib submodule.

* - Revert auto screen selection (incomplete)
- Revert nrF crypto engine (needs more work)
- add separate defines for not-auto-selecting screen lib.

* Define 2 new variants for RAK - with or without epaper

* Update variants

Co-authored-by: Sacha Weatherstone <sachaw100@hotmail.com>
Co-authored-by: Ben Meadors <thebentern@tuta.io>
2022-04-25 15:13:41 +10:00
Andre Kirchhoff
81588d8bdc Merge pull request #1400 from meshtastic/min_app_version-1.3
update minimum_app_version to 1.3.0
2022-04-24 20:17:23 -03:00
Andre Kirchhoff
3c1407c7d2 bump minimum app version requirement to 1.3.0 2022-04-24 19:52:32 -03:00
Ben Meadors
98c8eaaaf0 Moved sender short name method into protobuf module (#1398)
* Moved sender short name method into protobuf module

* Correct factory reset code for NRF (from 1.2)

* Use the correct fs abstraction

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-04-24 16:12:25 -05:00
Jm Casler
e7a825d1ba Merge pull request #1394 from GUVWAF/master
Implement listen-before-talk mechanism
2022-04-23 11:08:48 -07:00
GUVWAF
1d2551350d Merge branch 'master' of https://github.com/GUVWAF/Meshtastic-device 2022-04-23 19:01:53 +02:00
GUVWAF
a13157ebde Rename setRandomDelay() function 2022-04-23 18:57:45 +02:00
Ben Meadors
a0971ebe9c Merge branch 'master' into master 2022-04-23 08:46:02 -05:00
Ben Meadors
8733bcb52e Peg espressif platform version to 3.5.0 2022-04-23 08:42:26 -05:00
Ben Meadors
823e6cb1ed Merge branch 'master' into master 2022-04-22 07:56:50 -05:00
Ben Meadors
29e378a11e Link to open collective from contributors badge 2022-04-22 07:49:26 -05:00
GUVWAF
692278343b Merge branch 'master' of https://github.com/GUVWAF/Meshtastic-device 2022-04-20 20:16:39 +02:00
GUVWAF
c60d4c1ecc Implement listen-before-talk mechanism
- Function setRandomDelay() calls either startTransmitTimer() or startTransmitTimerSNR()
- After coming back from Rx/Tx-ing, call setRandomDelay()
- If channel is currently busy, call setRandomDelay()
2022-04-20 20:09:12 +02:00
GUVWAF
6d01f9aa89 Add isChannelActive() function to radio interface 2022-04-20 20:04:44 +02:00
GUVWAF
616c7d7b0e Expose front() function in MeshPacketQueue 2022-04-20 19:58:52 +02:00
Jm Casler
6b012ca5b0 Add fiscal contributors badge 2022-04-19 22:41:00 -07:00
Thomas Göttgens
93466baa87 Merge pull request #1393 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-04-19 23:08:29 +02:00
Thomas Göttgens
137328f567 Merge branch 'master' into create-pull-request/patch 2022-04-19 22:52:44 +02:00
Thomas Göttgens
838f00c7d7 Merge pull request #1391 from D4rk4/master
Brother EP-44 support
2022-04-19 22:52:16 +02:00
Dmitry Galenko
293921e95a Brother EP-44 support 2022-04-19 22:37:04 +02:00
caveman99
b82bf5c729 [create-pull-request] automated change 2022-04-19 20:26:22 +00:00
Jm Casler
90df7c2488 bump to 1.3.8 2022-04-18 17:20:03 -07:00
Jm Casler
8c1a81c03a Merge branch 'compression' into master 2022-04-18 17:02:45 -07:00
Jm Casler
6fe9f0b42f Disable compression / decompression (for testing) 2022-04-18 17:00:36 -07:00
Thomas Göttgens
43f6f61472 Merge pull request #1387 from meshtastic/patch-1
tryfix #1363
2022-04-18 23:01:07 +02:00
Thomas Göttgens
ed62b6916c tryfix #1363
Ask for the register several times and only go on if the answer is the same in 2 consecutive tries.
2022-04-18 22:46:45 +02:00
Thomas Göttgens
cf45e4fce5 Merge pull request #1386 from meshtastic/patch-1
Remove References to Pre-1.2 Preffile
2022-04-18 22:19:58 +02:00
Thomas Göttgens
136e2e96f7 Remove References to Pre-1.2 Preffile
1.3+ need a clean install anyway, so no point migrating these any more.
2022-04-18 21:55:58 +02:00
Jm Casler
7c071e2361 updating proto submodule to latest 2022-04-18 12:29:20 -07:00
Thomas Göttgens
0b85e97087 Merge pull request #1385 from meshtastic/oem-screen
Enable OEM Bootlogo, needs protobuf update
2022-04-18 18:43:47 +02:00
Thomas Göttgens
81d1cc1003 Merge branch 'oem-screen' of github.com:meshtastic/Meshtastic-device into oem-screen 2022-04-18 18:27:37 +02:00
Thomas Göttgens
748416d9e3 protobuf update 2022-04-18 18:27:17 +02:00
Thomas Göttgens
da6d49385c Merge branch 'master' into oem-screen 2022-04-18 18:18:19 +02:00
Thomas Göttgens
f279f9614e Enable OEM Bootlogo, needs protobuf update 2022-04-18 18:11:17 +02:00
Sacha Weatherstone
9097475149 Add Repobeats stats image to readme 2022-04-18 23:56:16 +10:00
Jm Casler
5327d6162a remove targz library 2022-04-15 23:17:30 -07:00
Jm Casler
5d7990667d Max nodes to 64 and remove targz 2022-04-15 23:16:40 -07:00
Jm Casler
79a41bd81c updating proto submodule to latest 2022-04-15 22:30:21 -07:00
Jm Casler
6a3d81eff8 Merge pull request #1383 from mc-hamster/compression
Change to unishox library
2022-04-15 20:46:04 -07:00
Jm Casler
7cd66b2b68 Merge branch 'meshtastic:master' into compression 2022-04-15 20:45:44 -07:00
Jm Casler
8124ecbfd8 Change to unishox library 2022-04-15 18:11:17 -07:00
Jm Casler
7df1a64b52 Merge pull request #1382 from mc-hamster/compression
Updated welcome screen w/ text, pages and logo
2022-04-14 21:33:19 -07:00
Jm Casler
e51b7c3c32 Merge branch 'meshtastic:master' into compression 2022-04-14 21:32:52 -07:00
Jm Casler
0c285aac6e enable welcome text 2022-04-14 21:32:00 -07:00
Jm Casler
fbeb554186 Merge branch 'compression' of https://github.com/mc-hamster/Meshtastic-device into compression 2022-04-14 21:31:38 -07:00
Jm Casler
87da779478 Updated welcome screen w/ text, pages and logo
Updated welcome screen w/ text, pages and logo
2022-04-14 21:31:31 -07:00
Jm Casler
1082c5d771 Merge pull request #1381 from mc-hamster/compression
Fix for welcome screen going over ble pairing
2022-04-14 21:05:21 -07:00
Jm Casler
3933d24d62 Merge branch 'meshtastic:master' into compression 2022-04-14 21:03:18 -07:00
Jm Casler
fc0508f254 Fix for welcome screen going over ble pairing 2022-04-14 21:02:52 -07:00
Jm Casler
bb22b6ec58 bump to 1.3.7 2022-04-14 16:15:19 -07:00
Jm Casler
ddb9678377 Merge pull request #1380 from mc-hamster/compression
Compression WIP
2022-04-14 16:14:31 -07:00
Jm Casler
dc20cbb672 one more fix for cppcheck 2022-04-14 15:57:31 -07:00
Jm Casler
a10ea604af Fixes for cppcheck errors 2022-04-14 15:51:48 -07:00
Jm Casler
fb1caa51d0 Merge branch 'meshtastic:master' into compression 2022-04-13 21:59:42 -07:00
Jm Casler
7e977aea00 Add welcome screen feature toggle 2022-04-13 21:59:25 -07:00
Jm Casler
ecc114f1cd temp work on compression 2022-04-13 19:23:35 -07:00
Balázs Kelemen
b76424db50 Make Observer to be able to observe multiple Observables. (#1234)
* Make Observer to be able to observe multiple Observables.

* Fix Observer destructor cleanup.

Co-authored-by: Sacha Weatherstone <sachaw100@hotmail.com>
2022-04-14 08:43:06 +10:00
Jm Casler
f511baba9a Bump to 1.3.6 2022-04-12 21:25:33 -07:00
Jm Casler
b056081d3c Merge branch 'meshtastic:master' into compression 2022-04-12 21:14:25 -07:00
Jm Casler
0e4699d8b6 updating proto submodule to latest 2022-04-12 21:13:35 -07:00
Ben Meadors
794167c701 Removed phone sds timeout (#1372) 2022-04-12 08:04:24 -05:00
amerinoj
b59368ca3c Updated pinut in variant tlorav2_1_16 (#1365)
* Added the last mac address bytes in bluetooth device name ESP32Bluetooth.cpp
Add default notification pinout to tlora_v2_1_16/variant.h

* updated ADC_MULTIPLIER  value for more accuracy

* Update variant.h

Updated LORA_RESET GPIO in this board is 23
Removed LORA_DIO1 35 , gpio 35 is a battery pin 
Removed LORA_DIO2 34, gpio 34 is unuse in this board

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2022-04-12 07:13:25 -05:00
Jm Casler
a4bdef4151 compression WIP
compression works. next is to store it in the proto as a oneof and then decompress it on use.
2022-04-11 22:12:04 -07:00
Jm Casler
478274aff1 Beginning of compression 2022-04-11 20:09:48 -07:00
Jm Casler
02066cc8b9 Merge pull request #1370 from mc-hamster/region_unset
Work around for issue with unknown age due to not having time
2022-04-11 19:18:59 -07:00
Jm Casler
309de52f5c Merge branch 'master' into region_unset 2022-04-11 18:53:54 -07:00
Jm Casler
340737f2a8 Work around for issue with unknown age due to not having time
Work around for issue with unknown age due to not having time
2022-04-11 18:53:29 -07:00
Jm Casler
9bd970c55e Merge pull request #1368 from mc-hamster/region_unset
Show welcome screen if region unset
2022-04-10 19:55:05 -07:00
Jm Casler
6eab8f84d1 Updated text for better fit 2022-04-10 19:34:13 -07:00
Jm Casler
a31bf71ec1 Merge branch 'region_unset' of https://github.com/mc-hamster/Meshtastic-device into region_unset 2022-04-10 19:27:17 -07:00
Jm Casler
14eef42762 Disable indicator on welcome screen. 2022-04-10 19:27:11 -07:00
Jm Casler
ef85b74cec Merge branch 'master' into region_unset 2022-04-10 19:15:47 -07:00
Jm Casler
16ae867c2d Show welcome screen if region unset 2022-04-10 19:15:10 -07:00
Jm Casler
0643dcd745 Merge pull request #1367 from mc-hamster/region_unset
Disable TX if region is unset
2022-04-09 23:08:59 -07:00
Jm Casler
69ed477040 Disable TX if region is unset 2022-04-09 22:42:43 -07:00
Jm Casler
0f5b0b5f00 Update README.md 2022-04-08 19:51:13 -07:00
Sacha Weatherstone
11323acb23 Update link to site 2022-04-08 13:40:41 +10:00
Ben Meadors
a20ba7e686 Add pca10059_diy_eink to boards matrix 2022-04-06 11:04:11 -05:00
Ben Meadors
10a7071300 Remove send owner interval (#1361)
* NodeInfo slimfast

* Removed send_owner_interval
2022-04-06 08:03:44 -05:00
Thomas Göttgens
eae9673ddb Merge pull request #1360 from meshtastic/1355-bug-crash-in-json-mqtt-bridge
fixes #1355
2022-04-06 14:28:23 +02:00
Thomas Göttgens
6e9cf82b68 fixes #1355 2022-04-06 14:11:39 +02:00
Thomas Göttgens
0035469790 Merge pull request #1358 from meshtastic/gpsfix
Improve T-Echo GPS Handling
2022-04-06 09:29:59 +02:00
Thomas Göttgens
028999697e Improve T-Echo GPS Handling 2022-04-06 09:18:55 +02:00
Mark Trevor Birss
b7aa1397c7 Add DIY nRF82540 PCA10059 4.2inch NiceRF 868 (#1354)
* Update build-all.sh

* Update configuration.h

* Update EInkDisplay2.cpp

* Create platformio.ini

* Create variant.cpp

* Create variant.h

* Update platformio.ini

* Update check-all.sh

* Create nordic_pca10059.json

* Update variant.h

* Update EInkDisplay2.cpp

* Update configuration.h

* Update platformio.ini

* Update EInkDisplay2.cpp

* Update variant.h

* Update EInkDisplay2.cpp

* Update configuration.h

* Update EInkDisplay2.cpp

* Update variant.h

* Update nordic_pca10059.json

* Update platformio.ini

* Update platformio.ini

* Update platformio.ini

* Update platformio.ini

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update configuration.h

* Update EInkDisplay2.cpp

* Update variant.h

* Update variant.h

* Update platformio.ini

* Update configuration.h

* Update configuration.h

* Update platformio.ini

* Update platformio.ini

* Update configuration.h

* Update platformio.ini

* Update configuration.h

* Update platformio.ini

* Update configuration.h

* Update configuration.h

* Update platformio.ini

* Update configuration.h

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-04-05 11:46:07 -05:00
github-actions[bot]
279def7911 [create-pull-request] automated change (#1356)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2022-04-05 11:31:13 -05:00
Ben Meadors
d73d3ca959 Update proto action to use nanopb 0.4.5 2022-04-05 11:29:54 -05:00
Michael Kleinhenz
998c90d326 Use JSON library for Web UI REST Endpoints (#1340)
* Updated rest endpoint json handling.

* Fixes, typos corrected.

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Sacha Weatherstone <sachaw100@hotmail.com>
2022-04-05 06:22:38 +10:00
neilhao
0c600363c8 add nano g1 (#1351)
* add nano g1

* Update platformio.ini

* Update configuration.h

* Revert platformio.ini to previous state

* Update configuration.h

* Update platformio.ini

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2022-04-04 20:16:19 +10:00
Thomas Göttgens
6c2d45d866 Merge pull request #1353 from meshtastic/patch-1
Add second scancode for SH1106
2022-04-04 09:12:09 +02:00
Thomas Göttgens
cf532496a4 Merge branch 'master' into patch-1 2022-04-04 08:52:07 +02:00
Thomas Göttgens
92d32f722d Add second scancode for SH1106
This display is found on the Nano G1
2022-04-04 08:51:29 +02:00
84 changed files with 3387 additions and 1452 deletions

View File

@@ -34,10 +34,10 @@ jobs:
- board: heltec-v2.1
- board: tbeam0.7
- board: meshtastic-diy-v1
- board: rak4631_5005
- board: rak4631_19003
- board: rak4631_5005_eink
- board: rak4631
- board: rak4631_eink
- board: t-echo
- board: nano-g1
runs-on: ubuntu-latest
steps:
@@ -92,6 +92,7 @@ jobs:
- board: heltec-v2.1
- board: tbeam0.7
- board: meshtastic-diy-v1
- board: nano-g1
runs-on: ubuntu-latest
steps:
@@ -117,7 +118,8 @@ jobs:
- name: Upgrade python tools
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
pip install -U platformio adafruit-nrfutil littlefs-python
pip install -U --pre meshtastic
- name: Upgrade platformio
run: |
@@ -158,10 +160,10 @@ jobs:
max-parallel: 2
matrix:
include:
- board: rak4631_5005
- board: rak4631_19003
- board: rak4631_5005_eink
- board: rak4631
- board: rak4631_eink
- board: t-echo
- board: pca10059_diy_eink
runs-on: ubuntu-latest
steps:
@@ -187,7 +189,8 @@ jobs:
- name: Upgrade python tools
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil
pip install -U platformio adafruit-nrfutil
pip install -U --pre meshtastic
- name: Upgrade platformio
run: |
@@ -234,7 +237,8 @@ jobs:
- name: Upgrade python tools
run: |
python -m pip install --upgrade pip
pip install -U platformio meshtastic adafruit-nrfutil
pip install -U platformio adafruit-nrfutil
pip install -U --pre meshtastic
- name: Upgrade platformio
run: |

View File

@@ -17,9 +17,9 @@ jobs:
- name: Download nanopb
run: |
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.4-linux-x86.tar.gz
tar xvzf nanopb-0.4.4-linux-x86.tar.gz
mv nanopb-0.4.4-linux-x86 nanopb-0.4.4
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.5-linux-x86.tar.gz
tar xvzf nanopb-0.4.5-linux-x86.tar.gz
mv nanopb-0.4.5-linux-x86 nanopb-0.4.5
- name: Re-generate protocol buffers
run: |

3
.gitmodules vendored
View File

@@ -1,9 +1,6 @@
[submodule "proto"]
path = proto
url = https://github.com/meshtastic/Meshtastic-protobufs.git
[submodule "sdk-nrfxlib"]
path = sdk-nrfxlib
url = https://github.com/nrfconnect/sdk-nrfxlib.git
[submodule "design"]
path = design
url = https://github.com/meshtastic/meshtastic-design.git

View File

@@ -1,7 +1,9 @@
# Meshtastic-device
[![Open in Visual Studio Code](https://open.vscode.dev/badges/open-in-vscode.svg)](https://open.vscode.dev/meshtastic/Meshtastic-device)
[![Continuous Integration](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml/badge.svg)](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml)
[![Continuous Integration](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main_matrix.yml/badge.svg)](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main_matrix.yml)
![GitHub all releases](https://img.shields.io/github/downloads/meshtastic/meshtastic-device/total)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/Meshtastic-device)](https://cla-assistant.io/meshtastic/Meshtastic-device)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg)](https://opencollective.com/meshtastic/)
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project.
@@ -16,3 +18,7 @@ Manual Method
[For nRF52 devices click here](https://meshtastic.org/docs/getting-started/flashing-nrf52)
For developer information and specific building instructions, please see the [developer documentation](https://meshtastic.org/docs/developers)
## Stats
![Alt](https://repobeats.axiom.co/api/embed/99a2cf5622bb4807f9e8c3b86589f1133cce58a2.svg 'Repobeats analytics image')

View File

@@ -5,11 +5,11 @@ set -e
VERSION=`bin/buildinfo.py long`
SHORT_VERSION=`bin/buildinfo.py short`
BOARDS_ESP32="rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1"
BOARDS_ESP32="rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 nano-g1"
#BOARDS_ESP32=tbeam
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
BOARDS_NRF52="rak4631_5005 rak4631_5005_eink rak4631_19003 t-echo"
BOARDS_NRF52="rak4631 rak4631_eink t-echo pca10059_diy_eink"
#BOARDS_NRF52=""
OUTDIR=release/latest

View File

@@ -13,7 +13,7 @@ if [[ $# -gt 0 ]]; then
# can override which environment by passing arg
BOARDS="$@"
else
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631_5005 rak4631_19003 rak11200 t-echo"
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631 rak4631_eink rak11200 t-echo pca10059_diy_eink"
fi
echo "BOARDS:${BOARDS}"

View File

@@ -0,0 +1,72 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
[
"0x239A",
"0x8029"
],
[
"0x239A",
"0x0029"
],
[
"0x239A",
"0x002A"
],
[
"0x239A",
"0x802A"
]
],
"usb_product": "PCA10059",
"mcu": "nrf52840",
"variant": "nRF52840 Dongle",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd"
},
"frameworks": [
"arduino"
],
"name": "nRF52840 Dongle",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle",
"vendor": "Nordic Semiconductor"
}

View File

@@ -1,55 +0,0 @@
{
"build": {
"arduino":{
"ldscript": "nrf52832_s132_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DNRF52832_XXAA -DNRF52",
"f_cpu": "64000000L",
"hwids": [
[
"0x10c4",
"0xea60"
]
],
"usb_product": "RAK815",
"mcu": "nrf52832",
"variant": "rak815",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS132",
"sd_name": "s132",
"sd_version": "6.1.1",
"sd_fwid": "0x00B7"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52832_xxAA",
"svd_path": "nrf52.svd"
},
"frameworks": [
"arduino"
],
"name": "RAK RAK815",
"upload": {
"maximum_ram_size": 65536,
"maximum_size": 524288,
"require_upload_port": true,
"speed": 115200,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
]
},
"url": "https://store.rakwireless.com/products/rak815-hybrid-location-tracker",
"vendor": "RAK"
}

View File

@@ -16,9 +16,8 @@ default_envs = tbeam
;default_envs = t-echo
;default_envs = nrf52840dk-geeksville
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
;default_envs = rak4631_5005
;default_envs = rak4631_5005_eink
;default_envs = rak4631_19003
;default_envs = nano-g1
;default_envs = pca10059_diy_eink
;default_envs = meshtastic-diy-v1
;default_envs = meshtastic-diy-v1.1
@@ -40,13 +39,13 @@ build_flags = -Wno-missing-field-initializers
monitor_speed = 921600
lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
https://github.com/meshtastic/esp8266-oled-ssd1306.git#53580644255b48ebb7a737343c6b4e71c7e11cf2 ; ESP8266_SSD1306
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
https://github.com/meshtastic/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
https://github.com/meshtastic/TinyGPSPlus.git
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it
SPI
@@ -82,7 +81,7 @@ lib_deps =
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
platform = espressif32
platform = espressif32@3.5.0
src_filter =
${arduino_base.src_filter} -<nrf52/>
upload_speed = 921600
@@ -100,7 +99,6 @@ lib_deps =
${environmental.lib_deps}
https://github.com/meshtastic/esp32_https_server.git
h2zero/NimBLE-Arduino@1.3.7
tobozo/ESP32-targz@^1.1.4
arduino-libraries/NTPClient@^3.1.0
lorol/LittleFS_esp32@^1.0.6
lib_ignore =
@@ -108,11 +106,15 @@ lib_ignore =
ESP32 BLE Arduino
platform_packages =
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#4cde0f5d412d2695184f32e8a47e9bea57b45276
; leave this commented out to avoid breaking Windows
; leave this commented out to avoid breaking Windows
;upload_port = /dev/ttyUSB0
;monitor_port = /dev/ttyUSB0
; Please don't delete these lines. JM uses them.
;upload_port = /dev/cu.SLAB_USBtoUART
;monitor_port = /dev/cu.SLAB_USBtoUART
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv
@@ -127,8 +129,7 @@ build_type = debug ; I'm debugging with ICE a lot now
; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME)
build_flags =
${arduino_base.build_flags} -Wno-unused-variable
-Isrc/nrf52
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
-Isrc/nrf52
src_filter =
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/>
lib_ignore =
@@ -140,7 +141,7 @@ build_flags = ${nrf52_base.build_flags}
lib_deps =
${arduino_base.lib_deps}
${environmental.lib_deps}
Adafruit nRFCrypto
https://github.com/Kongduino/Adafruit_nRFCrypto.git
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:nrf52840dk]
@@ -151,10 +152,3 @@ board = nrf52840_dk
[env:feather_nrf52832]
extends = nrf52_base
board = adafruit_feather_nrf52832
[env:rak815]
extends = nrf52_base
board = rak815
debug_tool = jlink
upload_protocol = jlink
monitor_speed = 115200

2
proto

Submodule proto updated: 31eaff0924...a578453b3c

Submodule sdk-nrfxlib deleted from e6e02cb83d

View File

@@ -135,7 +135,7 @@ class ButtonThread : public concurrency::OSThread
screen->adjustBrightness();
#endif
// If user button is held down for 5 seconds, shutdown the device.
if (millis() - longPressTime > 5 * 1000) {
if ((millis() - longPressTime > 5 * 1000) && (longPressTime > 0)) {
#ifdef TBEAM_V10
if (axp192_found == true) {
setLed(false);
@@ -144,7 +144,7 @@ class ButtonThread : public concurrency::OSThread
#elif NRF52_SERIES
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
if (!shutdown_on_long_stop) {
if ((!shutdown_on_long_stop) && (millis() > 30 * 1000)) {
screen->startShutdownScreen();
DEBUG_MSG("Shutdown from long press");
playBeep();
@@ -180,18 +180,22 @@ class ButtonThread : public concurrency::OSThread
static void userButtonPressedLongStart()
{
DEBUG_MSG("Long press start!\n");
longPressTime = millis();
if (millis() > 30 * 1000) {
DEBUG_MSG("Long press start!\n");
longPressTime = millis();
}
}
static void userButtonPressedLongStop()
{
DEBUG_MSG("Long press stop!\n");
longPressTime = 0;
if (shutdown_on_long_stop) {
playShutdownMelody();
delay(3000);
power->shutdown();
if (millis() > 30 * 1000){
DEBUG_MSG("Long press stop!\n");
longPressTime = 0;
if (shutdown_on_long_stop) {
playShutdownMelody();
delay(3000);
power->shutdown();
}
}
}
};

View File

@@ -63,7 +63,7 @@ class GPSStatus : public Status
int32_t getLatitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed latitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -75,7 +75,7 @@ class GPSStatus : public Status
int32_t getLongitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed longitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -87,7 +87,7 @@ class GPSStatus : public Status
int32_t getAltitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed altitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -105,7 +105,7 @@ class GPSStatus : public Status
bool matches(const GPSStatus *newStatus) const
{
#if GPS_EXTRAVERBOSE
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n",
newStatus->p.pos_timestamp, p.pos_timestamp);
#endif

View File

@@ -11,13 +11,13 @@ template <class T> class Observable;
*/
template <class T> class Observer
{
Observable<T> *observed = NULL;
std::list<Observable<T> *> observed;
public:
virtual ~Observer();
/// Stop watching our current obserable
void unobserve();
/// Stop watching the obserable
void unobserve(Observable<T> *o);
/// Start watching a specified observable
void observe(Observable<T> *o);
@@ -87,21 +87,21 @@ template <class T> class Observable
template <class T> Observer<T>::~Observer()
{
unobserve();
for (typename std::list<Observable<T> *>::const_iterator iterator = observed.begin(); iterator != observed.end();
++iterator) {
(*iterator)->removeObserver(this);
}
observed.clear();
}
template <class T> void Observer<T>::unobserve()
template <class T> void Observer<T>::unobserve(Observable<T> *o)
{
if (observed)
observed->removeObserver(this);
observed = NULL;
o->removeObserver(this);
observed.remove(o);
}
template <class T> void Observer<T>::observe(Observable<T> *o)
{
// We can only watch one thing at a time
assert(!observed);
observed = o;
observed.push_back(o);
o->addObserver(this);
}

View File

@@ -363,9 +363,6 @@ void PowerFSM_setup()
if (meshSds != UINT32_MAX)
powerFSM.add_timed_transition(lowPowerState, &stateSDS, meshSds * 1000, NULL, "mesh timeout");
// removing for now, because some users don't even have phones
// powerFSM.add_timed_transition(lowPowerState, &stateSDS, getPref_phone_sds_timeout_sec() * 1000, NULL, "phone
// timeout");
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
}

View File

@@ -72,7 +72,7 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
// If we are the first message on a report, include the header
if (!isContinuationMessage) {
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet);
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
if (rtc_sec > 0) {
long hms = rtc_sec % SEC_PER_DAY;
// hms += tz.tz_dsttime * SEC_PER_HOUR;

View File

@@ -25,6 +25,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <Arduino.h>
#ifdef RV3028_RTC
#include "Melopero_RV3028.h"
#endif
// -----------------------------------------------------------------------------
// Version
// -----------------------------------------------------------------------------
@@ -100,6 +104,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define GPS_TX_PIN 12
#endif
#ifndef TTGO_T_ECHO
#define GPS_UBLOX
#endif
// -----------------------------------------------------------------------------
// LoRa SPI
// -----------------------------------------------------------------------------
@@ -125,6 +133,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RTC_DATA_ATTR
#endif
// -----------------------------------------------------------------------------
// Feature toggles
// -----------------------------------------------------------------------------
// Disable use of the NTP library and related features
//#define DISABLE_NTP
// Disable the welcome screen and allow
// #define DISABLE_WELCOME_UNSET
// -----------------------------------------------------------------------------
// OLED & Input
// -----------------------------------------------------------------------------
@@ -240,6 +258,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define HW_VENDOR HardwareModel_T_ECHO
#elif defined(NANO_G1)
#define HW_VENDOR HardwareModel_NANO_G1
#elif defined(NORDIC_PCA10059)
#define HW_VENDOR HardwareModel_NRF52840_PCA10059
#elif NRF52_SERIES
#define HW_VENDOR HardwareModel_NRF52_UNKNOWN

60
src/debug/einkScan.h Normal file
View File

@@ -0,0 +1,60 @@
#include "../configuration.h"
#ifdef RAK4630
#include "../main.h"
#include <SPI.h>
void d_writeCommand(uint8_t c)
{
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, LOW);
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW);
SPI1.transfer(c);
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH);
if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, HIGH);
SPI1.endTransaction();
}
void d_writeData(uint8_t d)
{
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW);
SPI1.transfer(d);
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH);
SPI1.endTransaction();
}
unsigned long d_waitWhileBusy(uint16_t busy_time)
{
if (PIN_EINK_BUSY >= 0)
{
delay(1); // add some margin to become active
unsigned long start = micros();
while (1)
{
if (digitalRead(PIN_EINK_BUSY) != HIGH) break;
delay(1);
if (digitalRead(PIN_EINK_BUSY) != HIGH) break;
if (micros() - start > 10000000) break;
}
unsigned long elapsed = micros() - start;
(void) start;
return elapsed;
}
else return busy_time;
}
void scanEInkDevice(void)
{
SPI1.begin();
d_writeCommand(0x22);
d_writeData(0x83);
d_writeCommand(0x20);
eink_found = (d_waitWhileBusy(150) > 0) ? true : false;
if(eink_found)
DEBUG_MSG("EInk display found\n");
else
DEBUG_MSG("EInk display not found\n");
SPI1.end();
}
#endif

View File

@@ -6,21 +6,28 @@
uint8_t oled_probe(byte addr)
{
uint8_t r = 0;
uint8_t r_prev = 0;
uint8_t c = 0;
uint8_t o_probe = 0;
Wire.beginTransmission(addr);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom((int)addr, 1);
if (Wire.available()) {
r = Wire.read();
}
r &= 0x0f;
if (r == 0x08) {
o_probe = 2; // SH1106
} else if ( r == 0x03 || r == 0x06 || r == 0x07) {
o_probe = 1; // SSD1306
}
DEBUG_MSG("0x%x subtype probed\n", r);
do {
r_prev = r;
Wire.beginTransmission(addr);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom((int)addr, 1);
if (Wire.available()) {
r = Wire.read();
}
r &= 0x0f;
if (r == 0x08 || r == 0x00) {
o_probe = 2; // SH1106
} else if ( r == 0x03 || r == 0x06 || r == 0x07) {
o_probe = 1; // SSD1306
}
c++;
} while ((r != r_prev) && (c < 4));
DEBUG_MSG("0x%x subtype probed in %i tries \n", r, c);
return o_probe;
}
@@ -47,6 +54,16 @@ void scanI2Cdevice(void)
DEBUG_MSG("unknown display found\n");
}
}
#ifdef RV3028_RTC
if (addr == RV3028_RTC){
rtc_found = addr;
DEBUG_MSG("RV3028 RTC found\n");
Melopero_RV3028 rtc;
rtc.initI2C();
rtc.writeToRegister(0x35,0x07); // no Clkout
rtc.writeToRegister(0x37,0xB4);
}
#endif
if (addr == CARDKB_ADDR) {
cardkb_found = addr;
DEBUG_MSG("m5 cardKB found\n");
@@ -73,7 +90,7 @@ void scanI2Cdevice(void)
if (nDevices == 0)
DEBUG_MSG("No I2C devices found\n");
else
DEBUG_MSG("done\n");
DEBUG_MSG("%i I2C devices found\n",nDevices);
}
#else
void scanI2Cdevice(void) {}

View File

@@ -16,12 +16,6 @@ HardwareSerial *GPS::_serial_gps = &Serial1;
HardwareSerial *GPS::_serial_gps = NULL;
#endif
#ifdef GPS_I2C_ADDRESS
uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS;
#else
uint8_t GPS::i2cAddress = 0;
#endif
GPS *gps;
/// Multiple GPS instances might use the same serial port (in sequence), but we can
@@ -41,6 +35,75 @@ bool GPS::setupGPS()
#endif
#ifndef NO_ESP32
_serial_gps->setRxBufferSize(2048); // the default is 256
#endif
#ifdef TTGO_T_ECHO
// Switch to 4800 baud, then close and reopen port
_serial_gps->write("$PCAS01,0*1C\r\n");
delay(250);
_serial_gps->end();
delay(250);
_serial_gps->begin(4800);
delay(250);
// Initialize the L76K Chip, use GPS + GLONASS
_serial_gps->write("$PCAS04,5*1C\r\n");
delay(250);
// only ask for RMC and GGA
_serial_gps->write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
delay(250);
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
_serial_gps->write("$PCAS11,3*1E\r\n");
delay(250);
#endif
#ifdef GPS_UBLOX
// Set the UART port to output NMEA only
byte _message_nmea[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00,
0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x91, 0xAF};
_serial_gps->write(_message_nmea,sizeof(_message_nmea));
delay(250);
// disable GGL
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
0x05,0x3A};
_serial_gps->write(_message_GGL,sizeof(_message_GGL));
delay(250);
// disable GSA
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
0x06,0x41};
_serial_gps->write(_message_GSA,sizeof(_message_GSA));
delay(250);
// disable GSV
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x03, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
0x07,0x48};
_serial_gps->write(_message_GSV,sizeof(_message_GSV));
delay(250);
// disable VTG
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
0x09,0x56};
_serial_gps->write(_message_VTG,sizeof(_message_VTG));
delay(250);
// enable RMC
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x09,0x54};
_serial_gps->write(_message_RMC,sizeof(_message_RMC));
delay(250);
// enable GGA
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
0xF0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x05, 0x38};
_serial_gps->write(_message_GGA,sizeof(_message_GGA));
delay(250);
#endif
}
@@ -76,8 +139,8 @@ bool GPS::setup()
GPS::~GPS()
{
// we really should unregister our sleep observer
notifySleepObserver.unobserve();
notifyDeepSleepObserver.unobserve();
notifySleepObserver.unobserve(&notifySleep);
notifyDeepSleepObserver.unobserve(&notifyDeepSleep);
}
bool GPS::hasLock() { return hasValidLocation; }
@@ -306,10 +369,6 @@ int GPS::prepareDeepSleep(void *unused)
return 0;
}
#ifdef GPS_TX_PIN
#include "UBloxGPS.h"
#endif
#ifndef NO_GPS
#include "NMEAGPS.h"
#endif
@@ -326,25 +385,9 @@ GPS *createGps()
#else
DEBUG_MSG("Using MSL altitude model\n");
#endif
// If we don't have bidirectional comms, we can't even try talking to UBLOX
#ifdef GPS_TX_PIN
// Init GPS - first try ublox
UBloxGPS *ublox = new UBloxGPS();
if (!ublox->setup()) {
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
delete ublox;
ublox = NULL;
} else {
DEBUG_MSG("Using UBLOX Mode\n");
return ublox;
}
#endif
if (GPS::_serial_gps) {
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NMEA at 9600 baud.
DEBUG_MSG("Using NMEA Mode\n");
GPS *new_gps = new NMEAGPS();
new_gps->setup();
return new_gps;

View File

@@ -40,9 +40,6 @@ class GPS : private concurrency::OSThread
/** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps;
/** If !0 we will attempt to connect to the GPS over I2C */
static uint8_t i2cAddress;
Position p = Position_init_default;
GPS() : concurrency::OSThread("GPS") {}

View File

@@ -64,11 +64,12 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
t.tm_mon = d.month() - 1;
t.tm_year = d.year() - 1900;
t.tm_isdst = false;
DEBUG_MSG("NMEA GPS time %d-%d-%d %d:%d:%d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t);
return true;
if (t.tm_mon > -1){
DEBUG_MSG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t);
return true;
} else
return false;
} else
return false;
}
@@ -128,8 +129,16 @@ bool NMEAGPS::lookForLocation()
auto loc = reader.location.value();
// Bail out EARLY to avoid overwriting previous good data (like #857)
if(toDegInt(loc.lat) == 0) {
DEBUG_MSG("Ignoring bogus NMEA position\n");
if (toDegInt(loc.lat) > 900000000) {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("Bail out EARLY on LAT %i\n",toDegInt(loc.lat));
#endif
return false;
}
if (toDegInt(loc.lng) > 1800000000) {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("Bail out EARLY on LNG %i\n",toDegInt(loc.lng));
#endif
return false;
}

View File

@@ -1,5 +1,6 @@
#include "RTC.h"
#include "configuration.h"
#include "main.h"
#include <sys/time.h>
#include <time.h>
@@ -18,14 +19,35 @@ static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only upda
void readFromRTC()
{
struct timeval tv; /* btw settimeofday() is helpfull here too*/
#ifdef RV3028_RTC
if(rtc_found == RV3028_RTC) {
uint32_t now = millis();
Melopero_RV3028 rtc;
rtc.initI2C();
tm t;
t.tm_year = rtc.getYear() - 1900;
t.tm_mon = rtc.getMonth() - 1;
t.tm_mday = rtc.getDate();
t.tm_hour = rtc.getHour();
t.tm_min = rtc.getMinute();
t.tm_sec = rtc.getSecond();
tv.tv_sec = mktime(&t);
tv.tv_usec = 0;
DEBUG_MSG("Read RTC time from RV3028 as %ld\n", tv.tv_sec);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
if (currentQuality == RTCQualityNone) {
currentQuality = RTCQualityDevice;
}
}
#else
if (!gettimeofday(&tv, NULL)) {
uint32_t now = millis();
DEBUG_MSG("Read RTC time as %ld (cur millis %u) quality=%d\n", tv.tv_sec, now, currentQuality);
DEBUG_MSG("Read RTC time as %ld\n", tv.tv_sec);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
}
#endif
}
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
@@ -55,12 +77,20 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
zeroOffsetSecs = tv->tv_sec;
// If this platform has a setable RTC, set it
#ifndef NO_ESP32
#ifdef RV3028_RTC
if(rtc_found == RV3028_RTC) {
Melopero_RV3028 rtc;
rtc.initI2C();
tm *t = localtime(&tv->tv_sec);
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
DEBUG_MSG("RV3028_RTC setTime %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);
}
#elif !defined(NO_ESP32)
settimeofday(tv, NULL);
#endif
// nrf52 doesn't have a readable RTC (yet - software not written)
#if defined(PORTDUINO) || !defined(NO_ESP32)
#if defined(PORTDUINO) || !defined(NO_ESP32) || defined(RV3028_RTC)
readFromRTC();
#endif

View File

@@ -5,17 +5,21 @@
#include <Arduino.h>
enum RTCQuality {
/// We haven't had our RTC set yet
RTCQualityNone = 0,
/// We got time from an onboard peripheral after boot.
RTCQualityDevice = 1,
/// Some other node gave us a time we can use
RTCQualityFromNet = 1,
RTCQualityFromNet = 2,
/// Our time is based on NTP
RTCQualityNTP= 2,
RTCQualityNTP= 3,
/// Our time is based on our own GPS
RTCQualityGPS = 3
RTCQualityGPS = 4
};
RTCQuality getRTCQuality();

View File

@@ -1,328 +0,0 @@
#include "configuration.h"
#include "UBloxGPS.h"
#include "RTC.h"
#include "error.h"
#include "sleep.h"
#include <assert.h>
// if gps_update_interval below this value, do not powercycle the GPS
#define UBLOX_POWEROFF_THRESHOLD 90
#define PDOP_INVALID 9999
// #define UBX_MODE_NMEA
extern RadioConfig radioConfig;
UBloxGPS::UBloxGPS() {}
bool UBloxGPS::tryConnect()
{
bool c = false;
if (_serial_gps)
c = ublox.begin(*_serial_gps);
if (!c && i2cAddress) {
extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which
// supports the newer API
neo6M = true;
c = ublox.begin(Wire, i2cAddress);
}
if (c)
setConnected();
return c;
}
bool UBloxGPS::setupGPS()
{
GPS::setupGPS();
// uncomment to see debug info
// ublox.enableDebugging(Serial);
// try a second time, the ublox lib serial parsing is buggy?
// see https://github.com/meshtastic/Meshtastic-device/issues/376
for (int i = 0; (i < 3) && !tryConnect(); i++)
delay(500);
if (isConnected()) {
#ifdef UBX_MODE_NMEA
DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n");
DEBUG_MSG("- GPS errors below are related and safe to ignore\n");
#else
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
#endif
if (!setUBXMode())
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
#ifdef UBX_MODE_NMEA
return false;
#else
return true;
#endif
} else {
return false;
}
}
bool UBloxGPS::setUBXMode()
{
#ifdef UBX_MODE_NMEA
if (_serial_gps) {
ublox.setUART1Output(COM_TYPE_NMEA, 1000);
}
if (i2cAddress) {
ublox.setI2COutput(COM_TYPE_NMEA, 1000);
}
return false; // pretend initialization failed to force NMEA mode
#endif
if (_serial_gps) {
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
return false;
}
if (i2cAddress) {
if (!ublox.setI2COutput(COM_TYPE_UBX, 1000))
return false;
}
if (!ublox.setNavigationFrequency(1, 1000)) // Produce 4x/sec to keep the amount of time we stall in getPVT low
return false;
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
// assert(ok);
// ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
// assert(ok);
// per https://github.com/meshtastic/Meshtastic-device/issues/376 powerSaveMode might not work with the marginal
// TTGO antennas
// if (!ublox.powerSaveMode(true, 2000)) // use power save mode, the default timeout (1100ms seems a bit too tight)
// return false;
if (!ublox.saveConfiguration(3000))
return false;
return true;
}
/**
* Reset our GPS back to factory settings
*
* @return true for success
*/
bool UBloxGPS::factoryReset()
{
bool ok = false;
// It is useful to force back into factory defaults (9600baud, NMEA to test the behavior of boards that don't have
// GPS_TX connected)
ublox.factoryReset();
delay(5000);
tryConnect(); // sets isConnected
// try a second time, the ublox lib serial parsing is buggy?
for (int i = 0; (i < 3) && !tryConnect(); i++)
delay(500);
DEBUG_MSG("GPS Factory reset success=%d\n", isConnected());
if (isConnected())
ok = setUBXMode();
return ok;
}
/** Idle processing while GPS is looking for lock */
void UBloxGPS::whileActive()
{
ublox.flushPVT(); // reset ALL freshness flags first
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
// Ask for a new position fix - hopefully it will have results ready by next time
// the order here is important, because we only check for has latitude when reading
//ublox.getSIV(maxWait()); // redundant with getPDOP below
ublox.getPDOP(maxWait()); // will trigger getSOL on NEO6, getP on others
ublox.getP(maxWait()); // will trigger getPosLLH on NEO6, getP on others
// the fixType flag will be checked and updated in lookForLocation()
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool UBloxGPS::lookForTime()
{
if (ublox.moduleQueried.gpsSecond) {
/* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January
1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
struct tm t;
t.tm_sec = ublox.getSecond(0);
t.tm_min = ublox.getMinute(0);
t.tm_hour = ublox.getHour(0);
t.tm_mday = ublox.getDay(0);
t.tm_mon = ublox.getMonth(0) - 1;
t.tm_year = ublox.getYear(0) - 1900;
t.tm_isdst = false;
perhapsSetRTC(RTCQualityGPS, t);
return true;
}
return false;
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool UBloxGPS::lookForLocation()
{
bool foundLocation = false;
// check if a complete GPS solution set is available for reading
// (some of these, like lat/lon are redundant and can be removed)
if ( ! (ublox.moduleQueried.fixType &&
ublox.moduleQueried.latitude &&
ublox.moduleQueried.longitude &&
ublox.moduleQueried.altitude &&
ublox.moduleQueried.pDOP &&
ublox.moduleQueried.SIV &&
ublox.moduleQueried.gpsDay))
{
// Not ready? No problem! We'll try again later.
return false;
}
fixType = ublox.getFixType();
#ifdef UBLOX_EXTRAVERBOSE
DEBUG_MSG("FixType=%d\n", fixType);
#endif
// check if GPS has an acceptable lock
if (! hasLock()) {
ublox.flushPVT(); // reset ALL freshness flags
return false;
}
// read lat/lon/alt/dop data into temporary variables to avoid
// overwriting global variables with potentially invalid data
int32_t tmp_dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
int32_t tmp_lat = ublox.getLatitude(0);
int32_t tmp_lon = ublox.getLongitude(0);
int32_t tmp_alt_msl = ublox.getAltitudeMSL(0);
int32_t tmp_alt_hae = ublox.getAltitude(0);
int32_t max_dop = PDOP_INVALID;
if (radioConfig.preferences.gps_max_dop)
max_dop = radioConfig.preferences.gps_max_dop * 100; // scaling
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
// don't read it here - it will generate an ignored getPVT command on the 6ms
// heading = ublox.getHeading(0);
// read positional timestamp
struct tm t;
t.tm_sec = ublox.getSecond(0);
t.tm_min = ublox.getMinute(0);
t.tm_hour = ublox.getHour(0);
t.tm_mday = ublox.getDay(0);
t.tm_mon = ublox.getMonth(0) - 1;
t.tm_year = ublox.getYear(0) - 1900;
t.tm_isdst = false;
time_t tmp_ts = mktime(&t);
// FIXME - can opportunistically attempt to set RTC from GPS timestamp?
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
// FIXME - NULL ISLAND is a real location on Earth!
foundLocation = (tmp_lat != 0) && (tmp_lon != 0) &&
(tmp_lat <= 900000000) && (tmp_lat >= -900000000) &&
(tmp_dop < max_dop);
// only if entire dataset is valid, update globals from temp vars
if (foundLocation) {
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
p.longitude_i = tmp_lon;
p.latitude_i = tmp_lat;
if (fixType > 2) {
// if fix is 2d, ignore altitude data
p.altitude = tmp_alt_msl / 1000;
p.altitude_hae = tmp_alt_hae / 1000;
p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000;
} else {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("no altitude data (fixType=%d)\n", fixType);
#endif
// clean up old values in case it's a 3d-2d fix transition
p.altitude = p.altitude_hae = p.alt_geoid_sep = 0;
}
p.pos_timestamp = tmp_ts;
p.PDOP = tmp_dop;
p.fix_type = fixType;
p.sats_in_view = ublox.getSIV(0);
// In debug logs, identify position by @timestamp:stage (stage 1 = birth)
DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts);
} else {
// INVALID solution - should never happen
DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n",
tmp_lat, tmp_lon, tmp_alt_hae, tmp_dop);
}
ublox.flushPVT(); // reset ALL freshness flags at the end
return foundLocation;
}
bool UBloxGPS::hasLock()
{
if (radioConfig.preferences.gps_accept_2d)
return (fixType >= 2 && fixType <= 4);
else
return (fixType >= 3 && fixType <= 4);
}
bool UBloxGPS::whileIdle()
{
// if using i2c or serial look too see if any chars are ready
return ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
}
/// If possible force the GPS into sleep/low power mode
/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up
void UBloxGPS::sleep()
{
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
ublox.powerOff();
// setGPSPower(false);
}
}
void UBloxGPS::wake()
{
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
fixType = 0; // assume we have no fix yet
}
// this is idempotent
setGPSPower(true);
// Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff()
// Give time for the GPS to boot
// delay(200);
}

View File

@@ -1,72 +0,0 @@
#pragma once
#include "GPS.h"
#include "Observer.h"
#include "SparkFun_Ublox_Arduino_Library.h"
/**
* A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class UBloxGPS : public GPS
{
SFE_UBLOX_GPS ublox;
uint8_t fixType = 0;
public:
UBloxGPS();
/**
* Reset our GPS back to factory settings
*
* @return true for success
*/
bool factoryReset() override;
protected:
/**
* Returns true if we succeeded
*/
virtual bool setupGPS() override;
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle() override;
/** Idle processing while GPS is looking for lock */
virtual void whileActive() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation() override;
virtual bool hasLock() override;
/// If possible force the GPS into sleep/low power mode
virtual void sleep() override;
virtual void wake() override;
private:
/// Attempt to connect to our GPS, returns false if no gps is present
bool tryConnect();
/// Switch to our desired operating mode and save the settings to flash
/// returns true for success
bool setUBXMode();
uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ }
};

View File

@@ -1,6 +1,7 @@
#include "configuration.h"
#ifdef HAS_EINK
#include "main.h"
#include "EInkDisplay2.h"
#include "SPILock.h"
#include <SPI.h>
@@ -25,6 +26,11 @@
//1.54 inch 200x200 - GxEPD2_154_M09
//#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
#elif defined(PCA10059)
//4.2 inch 300x400 - GxEPD2_420_M01
#define TECHO_DISPLAY_MODEL GxEPD2_420_M01
#endif
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
@@ -47,6 +53,11 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
//GxEPD2_154_M09
//setGeometry(GEOMETRY_RAWMODE, 200, 200);
#elif defined(PCA10059)
//GxEPD2_420_M01
setGeometry(GEOMETRY_RAWMODE, 300, 400);
#endif
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
@@ -71,8 +82,8 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint64_t y = 0; y < displayHeight; y++) {
for (uint64_t x = 0; x < displayWidth; x++) {
for (uint32_t y = 0; y < displayHeight; y++) {
for (uint32_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * displayWidth];
@@ -81,11 +92,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
}
}
#if defined(TTGO_T_ECHO)
DEBUG_MSG("Updating T-ECHO E-Paper... ");
#elif defined(RAK4630)
DEBUG_MSG("Updating RAK4361_5005 E-Paper... ");
#endif
DEBUG_MSG("Updating E-Paper... ");
#if defined(TTGO_T_ECHO)
// ePaper.Reset(); // wake the screen from sleep
@@ -101,6 +108,8 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
// 4.2 inch 300x400 - GxEPD2_420_M01
//adafruitDisplay->nextPage();
#elif defined(PCA10059)
adafruitDisplay->nextPage();
#endif
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
@@ -163,18 +172,54 @@ bool EInkDisplay::connect()
}
#elif defined(RAK4630)
{
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
if (eink_found) {
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
adafruitDisplay->setRotation(3);
//For 1.54, 2.9 and 4.2
//adafruitDisplay->setRotation(1);
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
adafruitDisplay->setRotation(3);
//For 1.54, 2.9 and 4.2
//adafruitDisplay->setRotation(1);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
} else {
(void)adafruitDisplay;
}
}
#elif defined(PCA10059)
{
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
adafruitDisplay->setRotation(3);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
}
#endif

View File

@@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graphics/images.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "mesh/generated/deviceonly.pb.h"
#include "mesh/Channels.h"
#include "modules/TextMessageModule.h"
#include "sleep.h"
@@ -44,6 +45,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
using namespace meshtastic; /** @todo remove */
extern bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct);
namespace graphics
{
@@ -77,6 +80,10 @@ static char ourId[5];
// GeoCoord object for the screen
GeoCoord geoCoord;
// OEM Config File
static const char *oemConfigFile = "/prefs/oem.proto";
OEMStore oemStore;
#ifdef SHOW_REDRAWS
static bool heartbeat = false;
#endif
@@ -148,6 +155,54 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1
drawIconScreen(region, display, state, x, y);
}
static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// draw an xbm image.
// Please note that everything that should be transitioned
// needs to be drawn relative to x and y
// draw centered icon left to right and centered above the one line of app text
display->drawXbm(x + (SCREEN_WIDTH - oemStore.oem_icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - oemStore.oem_icon_height) / 2 + 2,
oemStore.oem_icon_width, oemStore.oem_icon_height, (const uint8_t *)oemStore.oem_icon_bits.bytes);
switch(oemStore.oem_font){
case 0:
display->setFont(FONT_SMALL);
break;
case 2:
display->setFont(FONT_LARGE);
break;
default:
display->setFont(FONT_MEDIUM);
break;
}
display->setTextAlignment(TEXT_ALIGN_LEFT);
const char *title = oemStore.oem_text;
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
display->setFont(FONT_SMALL);
// Draw region in upper left
if (upperMsg)
display->drawString(x + 0, y + 0, upperMsg);
// Draw version in upper right
char buf[16];
snprintf(buf, sizeof(buf), "%s",
xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
screen->forceDisplay();
// FIXME - draw serial # somewhere?
}
static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// Draw region in upper left
const char *region = myRegion ? myRegion->name : NULL;
drawOEMIconScreen(region, display, state, x, y);
}
// Used on boot when a certificate is being created
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
@@ -168,6 +223,40 @@ static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16
}
}
// Used when booting without a region set
static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
if ((millis() / 10000) % 2) {
display->setFont(FONT_SMALL);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the");
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,");
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Flasher or CLI client.");
} else {
display->setFont(FONT_SMALL);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org");
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information.");
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "");
}
#ifndef NO_ESP32
yield();
esp_task_wdt_reset();
#endif
}
#ifdef HAS_EINK
/// Used on eink displays while in deep sleep
static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
@@ -256,7 +345,7 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
display->drawString(0 + x, 0 + y, tempBuf);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org");
}
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled
@@ -646,8 +735,18 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
else if (agoSecs < 120 * 60) // last 2 hrs
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
else
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
else {
uint32_t hours_in_month = 730;
// Only show hours ago if it's been less than 6 months. Otherwise, we may have bad
// data.
if ((agoSecs / 60 / 60) < (hours_in_month * 6)) {
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
} else {
snprintf(lastStr, sizeof(lastStr), "unknown age");
}
}
static char distStr[20];
strcpy(distStr, "? km"); // might not have location data
@@ -716,12 +815,25 @@ void _screen_header()
}
#endif
// #ifdef RAK4630
// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), dispdev_oled(address, sda, scl), ui(&dispdev)
// {
// address_found = address;
// cmdQueue.setReader(this);
// if (screen_found) {
// (void)dispdev;
// AutoOLEDWire dispdev = dispdev_oled;
// (void)ui;
// OLEDDisplayUi ui(&dispdev);
// }
// }
// #else
Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev)
{
address_found = address;
cmdQueue.setReader(this);
}
// #endif
/**
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
@@ -766,11 +878,11 @@ void Screen::setup()
useDisplay = true;
#ifdef AutoOLEDWire_h
dispdev.setDetected(screen_model);
dispdev.setDetected(screen_model);
#endif
// I think this is not needed - redundant with ui.init
// dispdev.resetOrientation();
// Load OEM config from Proto file if existent
loadProto(oemConfigFile, OEMStore_size, sizeof(oemConfigFile), OEMStore_fields, &oemStore);
// Initialising the UI will init the display too.
ui.init();
@@ -823,6 +935,7 @@ void Screen::setup()
// twice initially.
ui.update();
ui.update();
serialSinceMsec = millis();
// Subscribe to status updates
powerStatusObserver.observe(&powerStatus->onNewStatus);
@@ -853,7 +966,7 @@ int32_t Screen::runOnce()
return RUN_SAME;
}
// Show boot screen for first 3 seconds, then switch to normal operation.
// Show boot screen for first 5 seconds, then switch to normal operation.
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
static bool showingBootScreen = true;
if (showingBootScreen && (millis() > (5000 + serialSinceMsec))) {
@@ -862,6 +975,27 @@ int32_t Screen::runOnce()
showingBootScreen = false;
}
// If we have an OEM Boot screen, toggle after 2,5 seconds
if(strlen(oemStore.oem_text) > 0){
static bool showingOEMBootScreen = true;
if (showingOEMBootScreen && (millis() > (2500 + serialSinceMsec))) {
DEBUG_MSG("Switch to OEM screen...\n");
// Change frames.
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
ui.setFrames(bootOEMFrames, bootOEMFrameCount);
ui.update();
ui.update();
showingOEMBootScreen = false;
}
}
#ifndef DISABLE_WELCOME_UNSET
if (showingNormalScreen && radioConfig.preferences.region == RegionCode_Unset) {
setWelcomeFrames();
}
#endif
// Process incoming commands.
for (;;) {
ScreenCmd cmd;
@@ -975,6 +1109,20 @@ void Screen::setSSLFrames()
}
}
/* show a message that the SSL cert is being built
* it is expected that this will be used during the boot phase */
void Screen::setWelcomeFrames()
{
if (address_found) {
// DEBUG_MSG("showing Welcome frames\n");
ui.disableAllIndicators();
static FrameCallback welcomeFrames[] = {drawWelcomeScreen};
ui.setFrames(welcomeFrames, 1);
ui.update();
}
}
// restore our regular frame list
void Screen::setFrames()
{
@@ -1366,7 +1514,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
}
auto mode = "";
if (channels.getPrimary().modem_config == 0) {
mode = "VLongSlow";
} else if (channels.getPrimary().modem_config == 1) {
@@ -1380,7 +1528,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
} else if (channels.getPrimary().modem_config == 5) {
mode = "ShortSlow";
} else if (channels.getPrimary().modem_config == 6) {
mode = "ShortFast";
mode = "ShortFast";
} else {
mode = "Custom";
}
@@ -1409,7 +1557,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
else
uptime += String(seconds) + "s ";
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet);
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
if (rtc_sec > 0) {
long hms = rtc_sec % SEC_PER_DAY;
// hms += tz.tz_dsttime * SEC_PER_HOUR;
@@ -1432,8 +1580,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// Display Channel Utilization
char chUtil[13];
sprintf(chUtil, "ChUtil %2.0f%%", airTime->channelUtilizationPercent());
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil),
y + FONT_HEIGHT_SMALL * 1, chUtil);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
// Line 3
if (radioConfig.preferences.gps_format != GpsCoordinateFormat_GpsFormatDMS) // if DMS then don't draw altitude
@@ -1491,16 +1638,13 @@ int Screen::handleTextMessage(const MeshPacket *packet)
int Screen::handleUIFrameEvent(const UIFrameEvent *event)
{
if (showingNormalScreen) {
if (event->frameChanged)
{
if (event->frameChanged) {
setFrames(); // Regen the list of screens (will show new text message)
}
else if (event->needRedraw)
{
} else if (event->needRedraw) {
setFastFramerate();
// TODO: We might also want switch to corresponding frame,
// but we don't know the exact frame number.
//ui.switchToFrame(0);
// ui.switchToFrame(0);
}
}

View File

@@ -27,6 +27,10 @@ class Screen
#ifdef USE_ST7567
#include <ST7567Wire.h>
#elif defined(USE_SH1106)
#include <SH1106Wire.h>
#elif defined(USE_SSD1306)
#include <SSD1306Wire.h>
#else
// the SH1106/SSD1306 variant is auto-detected
#include <AutoOLEDWire.h>
@@ -235,6 +239,8 @@ class Screen : public concurrency::OSThread
/// Draws our SSL cert screen during boot (called from WebServer)
void setSSLFrames();
void setWelcomeFrames();
protected:
/// Updates the UI.
//
@@ -295,9 +301,16 @@ class Screen : public concurrency::OSThread
/// Holds state for debug information
DebugInfo debugInfo;
/// Display device
/** FIXME cleanup display abstraction */
#ifdef ST7735_CS
/// Display device
// #ifdef RAK4630
// EInkDisplay dispdev;
// AutoOLEDWire dispdev_oled;
#ifdef USE_SH1106
SH1106Wire dispdev;
#elif defined(USE_SSD1306)
SSD1306Wire dispdev;
#elif defined(ST7735_CS)
TFTDisplay dispdev;
#elif defined(HAS_EINK)
EInkDisplay dispdev;

View File

@@ -24,6 +24,7 @@
#include "shutdown.h"
#include "target_specific.h"
#include "debug/i2cScan.h"
#include "debug/einkScan.h"
#include "debug/axpDebug.h"
#include <Wire.h>
// #include <driver/rtc_io.h>
@@ -78,6 +79,11 @@ uint8_t cardkb_found;
// The I2C address of the Faces Keyboard (if found)
uint8_t faceskb_found;
// The I2C address of the RTC Module (if found)
uint8_t rtc_found;
bool eink_found = true;
uint32_t serialSinceMsec;
bool axp192_found;
@@ -150,6 +156,12 @@ void setup()
initDeepSleep();
// Testing this fix für erratic T-Echo boot behaviour
#if defined(TTGO_T_ECHO) && defined(PIN_EINK_PWR_ON)
pinMode(PIN_EINK_PWR_ON, OUTPUT);
digitalWrite(PIN_EINK_PWR_ON, HIGH);
#endif
#ifdef VEXT_ENABLE
pinMode(VEXT_ENABLE, OUTPUT);
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
@@ -208,6 +220,9 @@ void setup()
#endif
scanI2Cdevice();
#ifdef RAK4630
// scanEInkDevice();
#endif
// Buttons & LED
buttonThread = new ButtonThread();

View File

@@ -9,7 +9,9 @@ extern uint8_t screen_found;
extern uint8_t screen_model;
extern uint8_t cardkb_found;
extern uint8_t faceskb_found;
extern uint8_t rtc_found;
extern bool eink_found;
extern bool axp192_found;
extern bool isCharging;
extern bool isUSBPowered;

View File

@@ -1,250 +0,0 @@
#include "configuration.h"
#include "DSRRouter.h"
/* when we receive any packet
- sniff and update tables (especially useful to find adjacent nodes). Update user, network and position info.
- if we need to route() that packet, resend it to the next_hop based on our nodedb.
- if it is broadcast or destined for our node, deliver locally
- handle routereply/routeerror/routediscovery messages as described below
- then free it
routeDiscovery
- if we've already passed through us (or is from us), then it ignore it
- use the nodes already mentioned in the request to update our routing table
- if they were looking for us, send back a routereply
- if max_hops is zero and they weren't looking for us, drop (FIXME, send back error - I think not though?)
- if we receive a discovery packet, we use it to populate next_hop (if needed) towards the requester (after decrementing max_hops)
- if we receive a discovery packet, and we have a next_hop in our nodedb for that destination we send a (reliable) we send a route
reply towards the requester
when sending any reliable packet
- if timeout doing retries, send a routeError (nak) message back towards the original requester. all nodes eavesdrop on that
packet and update their route caches.
when we receive a routereply packet
- update next_hop on the node, if the new reply needs fewer hops than the existing one (we prefer shorter paths). fixme, someday
use a better heuristic
when we receive a routeError packet
- delete the route for that failed recipient, restartRouteDiscovery()
- if we receive routeerror in response to a discovery,
- fixme, eventually keep caches of possible other routes.
*/
ErrorCode DSRRouter::send(MeshPacket *p)
{
// We only consider multihop routing packets (i.e. those with dest set)
if (p->decoded.dest) {
// add an entry for this pending message
auto pending = startRetransmission(p);
// FIXME - when acks come in for this packet, we should _not_ delete the record unless the ack was from
// the final dest. We need to keep that record around until FIXME
// Also we should not retransmit multihop entries in that table at all
// If we have an entry in our routing tables, just send it, otherwise start a route discovery
NodeNum nextHop = getNextHop(p->decoded.dest);
if (nextHop) {
sendNextHop(nextHop, p); // start a reliable single hop send
} else {
pending->wantRoute = true;
// start discovery, but only if we don't already a discovery in progress for that node number
startDiscovery(p->decoded.dest);
}
return ERRNO_OK;
} else
return ReliableRouter::send(p);
}
void DSRRouter::sniffReceived(const MeshPacket *p, const Routing *c)
{
// Learn 0 hop routes by just hearing any adjacent nodes
// But treat broadcasts carefully, because when flood broadcasts go out they keep the same original "from". So we want to
// ignore rebroadcasts.
// this will also add records for any ACKs we receive for our messages
if (p->to != NODENUM_BROADCAST || p->hop_limit != HOP_RELIABLE) {
addRoute(getFrom(p), getFrom(p), 0); // We are adjacent with zero hops
}
if (c)
switch (c->which_variant) {
case Routing_route_request_tag:
// Handle route discovery packets (will be a broadcast message)
// FIXME - always start request with the senders nodenum
if (weAreInRoute(c->route_request)) {
DEBUG_MSG("Ignoring a route request that contains us\n");
} else {
updateRoutes(c->route_request,
true); // Update our routing tables based on the route that came in so far on this request
if (p->decoded.dest == getNodeNum()) {
// They were looking for us, send back a route reply (the sender address will be first in the list)
sendRouteReply(c->route_request);
} else {
// They were looking for someone else, forward it along (as a zero hop broadcast)
NodeNum nextHop = getNextHop(p->decoded.dest);
if (nextHop) {
// in our route cache, reply to the requester (the sender address will be first in the list)
sendRouteReply(c->route_request, nextHop);
} else {
// Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route)
resendRouteRequest(p);
}
}
}
break;
case Routing_route_reply_tag:
updateRoutes(c->route_reply, false);
// FIXME, if any of our current pending packets were waiting for this route, send them (and leave them as regular
// pending packets until ack arrives)
// FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our
// own...
break;
case Routing_error_reason_tag:
removeRoute(p->decoded.dest);
// FIXME: if any pending packets were waiting on this route, delete them
break;
default:
break;
}
// We simply ignore ACKs - because ReliableRouter will delete the pending packet for us
// Handle regular packets
if (p->to == getNodeNum()) { // Destined for us (at least for this hop)
// We need to route this packet to some other node
if (p->decoded.dest && p->decoded.dest != p->to) {
// if we have a route out, resend the packet to the next hop, otherwise return RouteError no-route available
NodeNum nextHop = getNextHop(p->decoded.dest);
if (nextHop) {
sendNextHop(nextHop, p); // start a reliable single hop send
} else {
// We don't have a route out
assert(p->decoded.source); // I think this is guaranteed by now
// FIXME - what if the current packet _is_ a route error packet?
sendRouteError(p, Routing_Error_NO_ROUTE);
}
// FIXME, stop local processing of this packet
}
if (c) {
// handle naks - convert them to route error packets
// All naks are generated locally, because we failed resending the packet too many times
PacketId nakId = c->error_reason ? p->decoded.request_id : 0;
if (nakId) {
auto pending = findPendingPacket(p->to, nakId);
if (pending &&
pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore
removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node
sendRouteError(p, Routing_Error_GOT_NAK);
}
}
}
}
ReliableRouter::sniffReceived(p, c);
}
/**
* Does our node appear in the specified route
*/
bool DSRRouter::weAreInRoute(const RouteDiscovery &route)
{
return true; // FIXME
}
/**
* Given a DSR route, use that route to update our DB of possible routes
*
* Note: routes are always listed in the same order - from sender to receipient (i.e. route_replies also use this some order)
*
* @param isRequest is true if we are looking at a route request, else we are looking at a reply
**/
void DSRRouter::updateRoutes(const RouteDiscovery &route, bool isRequest)
{
DEBUG_MSG("FIXME not implemented updateRoutes\n");
}
/**
* send back a route reply (the sender address will be first in the list)
*/
void DSRRouter::sendRouteReply(const RouteDiscovery &route, NodeNum toAppend)
{
DEBUG_MSG("FIXME not implemented sendRoute\n");
}
/**
* Given a nodenum return the next node we should forward to if we want to reach that node.
*
* @return 0 if no route found
*/
NodeNum DSRRouter::getNextHop(NodeNum dest)
{
DEBUG_MSG("FIXME not implemented getNextHop\n");
return 0;
}
/** Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route)
*
* We will bump down hop_limit in this call.
*/
void DSRRouter::resendRouteRequest(const MeshPacket *p)
{
DEBUG_MSG("FIXME not implemented resendRoute\n");
}
/**
* Record that forwarder can reach dest for us, but they will need numHops to get there.
* If our routing tables already have something that can reach that node in fewer hops we will keep the existing route
* instead.
*/
void DSRRouter::addRoute(NodeNum dest, NodeNum forwarder, uint8_t numHops)
{
DEBUG_MSG("FIXME not implemented addRoute\n");
}
/**
* Record that we no longer have a route to the dest
*/
void DSRRouter::removeRoute(NodeNum dest)
{
DEBUG_MSG("FIXME not implemented removeRoute\n");
}
/**
* Forward the specified packet to the specified node
*/
void DSRRouter::sendNextHop(NodeNum n, const MeshPacket *p)
{
DEBUG_MSG("FIXME not implemented sendNextHop\n");
}
/**
* Send a route error packet towards whoever originally sent this message
*/
void DSRRouter::sendRouteError(const MeshPacket *p, Routing_Error err)
{
DEBUG_MSG("FIXME not implemented sendRouteError\n");
}
/** make a copy of p, start discovery, but only if we don't
* already a discovery in progress for that node number. Caller has already scheduled this message for retransmission
* when the discovery is complete.
*/
void DSRRouter::startDiscovery(NodeNum dest)
{
DEBUG_MSG("FIXME not implemented startDiscovery\n");
}

View File

@@ -1,80 +0,0 @@
#include "ReliableRouter.h"
class DSRRouter : public ReliableRouter
{
protected:
/**
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
* update routing tables etc... based on what we overhear (even for messages not destined to our node)
*/
virtual void sniffReceived(const MeshPacket *p, const Routing *c) override;
/**
* Send a packet on a suitable interface. This routine will
* later free() the packet to pool. This routine is not allowed to stall.
* If the txmit queue is full it might return an error
*/
virtual ErrorCode send(MeshPacket *p) override;
private:
/**
* Does our node appear in the specified route
*/
bool weAreInRoute(const RouteDiscovery &route);
/**
* Given a DSR route, use that route to update our DB of possible routes
*
* Note: routes are always listed in the same order - from sender to receipient (i.e. route_replies also use this some order)
*
* @param isRequest is true if we are looking at a route request, else we are looking at a reply
**/
void updateRoutes(const RouteDiscovery &route, bool isRequest);
/**
* send back a route reply (the sender address will be first in the list)
*/
void sendRouteReply(const RouteDiscovery &route, NodeNum toAppend = 0);
/**
* Given a nodenum return the next node we should forward to if we want to reach that node.
*
* @return 0 if no route found
*/
NodeNum getNextHop(NodeNum dest);
/** Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route)
*
* We will bump down hop_limit in this call.
*/
void resendRouteRequest(const MeshPacket *p);
/**
* Record that forwarder can reach dest for us, but they will need numHops to get there.
* If our routing tables already have something that can reach that node in fewer hops we will keep the existing route
* instead.
*/
void addRoute(NodeNum dest, NodeNum forwarder, uint8_t numHops);
/**
* Record that we no longer have a route to the dest
*/
void removeRoute(NodeNum dest);
/**
* Forward the specified packet to the specified node
*/
void sendNextHop(NodeNum n, const MeshPacket *p);
/**
* Send a route error packet towards whoever originally sent this message
*/
void sendRouteError(const MeshPacket *p, Routing_Error err);
/** make a copy of p, start discovery, but only if we don't
* already a discovery in progress for that node number. Caller has already scheduled this message for retransmission
* when the discovery is complete.
*/
void startDiscovery(NodeNum dest);
};

View File

@@ -72,6 +72,16 @@ MeshPacket *MeshPacketQueue::dequeue()
return p;
}
MeshPacket *MeshPacketQueue::getFront()
{
if (empty()) {
return NULL;
}
auto *p = queue.front();
return p;
}
/** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */
MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id)
{

View File

@@ -28,6 +28,8 @@ class MeshPacketQueue
MeshPacket *dequeue();
MeshPacket *getFront();
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
MeshPacket *remove(NodeNum from, PacketId id);
};

View File

@@ -71,17 +71,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp)
printPacket("Forwarding to phone", mp);
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
fromNum++;
if (toPhoneQueue.numFree() == 0) {
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
}
MeshPacket *copied = packetPool.allocCopy(*mp);
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
sendToPhone((MeshPacket *)mp);
return 0;
}
@@ -161,12 +151,16 @@ bool MeshService::cancelSending(PacketId id)
return router->cancelSending(nodeDB.getNodeNum(), id);
}
void MeshService::sendToMesh(MeshPacket *p, RxSource src)
void MeshService::sendToMesh(MeshPacket *p, RxSource src, bool ccToPhone)
{
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
router->sendLocal(p, src);
if (ccToPhone) {
sendToPhone(p);
}
}
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
@@ -187,6 +181,20 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
}
}
void MeshService::sendToPhone(MeshPacket *p) {
if (toPhoneQueue.numFree() == 0) {
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
}
MeshPacket *copied = packetPool.allocCopy(*p);
perhapsDecode(copied);
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
fromNum++;
}
NodeInfo *MeshService::refreshMyNodeInfo()
{
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
@@ -224,7 +232,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
} else {
// The GPS has lost lock, if we are fixed position we should just keep using
// the old position
#if GPS_EXTRAVERBOSE
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("onGPSchanged() - lost validLocation\n");
#endif
if (radioConfig.preferences.fixed_position) {

View File

@@ -75,7 +75,7 @@ class MeshService
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
/// cache
void sendToMesh(MeshPacket *p, RxSource src = RX_SRC_LOCAL);
void sendToMesh(MeshPacket *p, RxSource src = RX_SRC_LOCAL, bool ccToPhone = false);
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
bool cancelSending(PacketId id);
@@ -83,6 +83,9 @@ class MeshService
/// Pull the latest power and time info into my nodeinfo
NodeInfo *refreshMyNodeInfo();
/// Send a packet to the phone
void sendToPhone(MeshPacket *p);
private:
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
/// returns 0 to allow futher processing

View File

@@ -95,14 +95,16 @@ bool NodeDB::resetRadioConfig()
nvs_flash_erase();
#endif
#ifdef NRF52_SERIES
// first, remove the "/prefs" (this removes most prefs)
FSCom.rmdir_r("/prefs");
// second, install default state (this will deal with the duplicate mac address issue)
installDefaultDeviceState();
// third, write to disk
saveToDisk();
Bluefruit.begin();
DEBUG_MSG("Clearing bluetooth bonds!\n");
bond_print_list(BLE_GAP_ROLE_PERIPH);
bond_print_list(BLE_GAP_ROLE_CENTRAL);
Bluefruit.Periph.clearBonds();
Bluefruit.Central.clearBonds();
#endif
@@ -215,7 +217,7 @@ void NodeDB::init()
myNodeInfo.error_address = 0;
// likewise - we always want the app requirements to come from the running appload
myNodeInfo.min_app_version = 20200; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
myNodeInfo.min_app_version = 20300; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
@@ -276,11 +278,9 @@ void NodeDB::pickNewNodeNum()
myNodeInfo.my_node_num = r;
}
static const char *preffileOld = "/db.proto";
static const char *preffile = "/prefs/db.proto";
static const char *radiofile = "/prefs/radio.proto";
static const char *channelfile = "/prefs/channels.proto";
// const char *preftmp = "/db.proto.tmp";
/** Load a protobuf from a file, return true for success */
bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct)
@@ -290,13 +290,6 @@ bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_
auto f = FSCom.open(filename);
// FIXME, temporary hack until every node in the universe is 1.2 or later - look for prefs in the old location (so we can
// preserve region)
if (!f && filename == preffile) {
filename = preffileOld;
f = FSCom.open(filename);
}
bool okay = false;
if (f) {
DEBUG_MSG("Loading %s\n", filename);
@@ -399,8 +392,6 @@ void NodeDB::saveToDisk()
saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig);
saveChannelsToDisk();
// remove any pre 1.2 pref files, turn on after 1.2 is in beta
// if(okay) FSCom.remove(preffileOld);
} else {
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
}

View File

@@ -141,12 +141,10 @@ extern NodeDB nodeDB;
# prefs.position_broadcast_secs = FIXME possibly broadcast only once an hr
prefs.wait_bluetooth_secs = 1 # Don't stay in bluetooth mode
prefs.mesh_sds_timeout_secs = never
prefs.phone_sds_timeout_sec = never
# try to stay in light sleep one full day, then briefly wake and sleep again
prefs.ls_secs = oneday
prefs.send_owner_interval = 2 # Send an owner packet every other network ping
prefs.position_broadcast_secs = 12 hours # send either position or owner every 12hrs
# get a new GPS position once per day
@@ -166,7 +164,6 @@ extern NodeDB nodeDB;
#define PREF_GET(name, defaultVal) \
inline uint32_t getPref_##name() { return radioConfig.preferences.name ? radioConfig.preferences.name : (defaultVal); }
PREF_GET(send_owner_interval, IF_ROUTER(2, 4))
PREF_GET(position_broadcast_secs, IF_ROUTER(12 * 60 * 60, 15 * 60))
// Defaulting Telemetry to the same as position interval for now
PREF_GET(telemetry_module_device_update_interval, IF_ROUTER(12 * 60 * 60, 15 * 60))
@@ -178,7 +175,6 @@ PREF_GET(wait_bluetooth_secs, IF_ROUTER(1, 60))
PREF_GET(screen_on_secs, 60)
PREF_GET(mesh_sds_timeout_secs, IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60))
PREF_GET(phone_sds_timeout_sec, IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60))
PREF_GET(sds_secs, 365 * 24 * 60 * 60)
// We default to sleeping (with bluetooth off for 5 minutes at a time). This seems to be a good tradeoff between

View File

@@ -48,7 +48,7 @@ void PhoneAPI::close()
if (state != STATE_SEND_NOTHING) {
state = STATE_SEND_NOTHING;
unobserve();
unobserve(&service.fromNumChanged);
releasePhonePacket(); // Don't leak phone packets on shutdown
onConnectionChanged(false);

View File

@@ -48,6 +48,17 @@ template <class T> class ProtobufModule : protected SinglePortModule
return p;
}
/**
* Gets the short name from the sender of the mesh packet
* Returns "???" if unknown sender
*/
const char *getSenderShortName(const MeshPacket &mp)
{
auto node = nodeDB.getNode(getFrom(&mp));
const char *sender = (node) ? node->user.short_name : "???";
return sender;
}
private:
/** Called to handle a particular incoming message

View File

@@ -176,6 +176,25 @@ void RF95Interface::startReceive()
enableInterrupt(isrRxLevel0);
}
bool RF95Interface::isChannelActive()
{
// check if we can detect a LoRa preamble on the current channel
int16_t result;
setTransmitEnable(false);
setStandby(); // needed for smooth transition
result = lora->scanChannel();
if (result == PREAMBLE_DETECTED) {
// DEBUG_MSG("Channel is busy!\n");
return true;
}
assert(result != ERR_WRONG_MODEM);
// DEBUG_MSG("Channel is free!\n");
return false;
}
/** Could we send right now (i.e. either not actively receving or transmitting)? */
bool RF95Interface::isActivelyReceiving()
{

View File

@@ -40,6 +40,9 @@ class RF95Interface : public RadioLibInterface
*/
virtual void enableInterrupt(void (*callback)()) { lora->setDio0Action(callback); }
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() override;
/** are we actively receiving a packet (only called during receiving state) */
virtual bool isActivelyReceiving() override;

View File

@@ -1,8 +1,8 @@
#include "configuration.h"
#include "RadioLibInterface.h"
#include "MeshTypes.h"
#include "NodeDB.h"
#include "SPILock.h"
#include "configuration.h"
#include "error.h"
#include "mesh-pb-constants.h"
#include <pb_decode.h>
@@ -93,8 +93,15 @@ bool RadioLibInterface::canSendImmediately()
/// bluetooth comms code. If the txmit queue is empty it might return an error
ErrorCode RadioLibInterface::send(MeshPacket *p)
{
if (disabled || radioConfig.preferences.is_lora_tx_disabled) {
DEBUG_MSG("send - lora_tx_disabled\n");
if (radioConfig.preferences.region != RegionCode_Unset) {
if (disabled || radioConfig.preferences.is_lora_tx_disabled) {
DEBUG_MSG("send - lora_tx_disabled\n");
packetPool.release(p);
return ERRNO_DISABLED;
}
} else {
DEBUG_MSG("send - lora_tx_disabled because RegionCode_Unset\n");
packetPool.release(p);
return ERRNO_DISABLED;
}
@@ -111,21 +118,10 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
return res;
}
// We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent
// in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was not generated locally.
* This assumption is valid because of the offset generated by the radio to account for the noise
* floor.
*/
if (p->rx_snr == 0 && p->rx_rssi == 0) {
startTransmitTimer(true);
} else {
// If there is a SNR, start a timer scaled based on that SNR.
DEBUG_MSG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr);
startTransmitTimerSNR(p->rx_snr);
}
// set (random) transmit delay to let others reconfigure their radio,
// to avoid collisions and implement timing-based flooding
// DEBUG_MSG("Set random delay before transmitting.\n");
setTransmitDelay();
return res;
#else
@@ -158,8 +154,8 @@ bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
/** radio helper thread callback.
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and
wait a random delay of 50 to 200 ms to make sure we are not stomping on someone else. The 50ms delay at the beginning ensures all
possible listeners have had time to finish processing the previous packet and now have their radio in RX state. The up to 200ms
wait a random delay of 100ms to 100ms+shortPacketMsec to make sure we are not stomping on someone else. The 100ms delay at the beginning ensures all
possible listeners have had time to finish processing the previous packet and now have their radio in RX state. The up to 100ms+shortPacketMsec
random delay gives a chance for all possible senders to have high odds of detecting that someone else started transmitting first
and then they will wait until that packet finishes.
@@ -186,20 +182,26 @@ void RadioLibInterface::onNotify(uint32_t notification)
case TRANSMIT_DELAY_COMPLETED:
// DEBUG_MSG("delay done\n");
// If we are not currently in receive mode, then restart the timer and try again later (this can happen if the main thread
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
if (!txQueue.empty()) {
if (!canSendImmediately()) {
startTransmitTimer(); // try again in a little while
// DEBUG_MSG("Currently Rx/Tx-ing: set random delay\n");
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
} else {
// Send any outgoing packets we have ready
MeshPacket *txp = txQueue.dequeue();
assert(txp);
startSend(txp);
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
// DEBUG_MSG("Channel is active: set random delay\n");
setTransmitDelay(); // reset random delay
} else {
// Send any outgoing packets we have ready
MeshPacket *txp = txQueue.dequeue();
assert(txp);
startSend(txp);
// Packet has been sent, count it toward our TX airtime utilization.
uint32_t xmitMsec = getPacketTime(txp);
airTime->logAirtime(TX_LOG, xmitMsec);
// Packet has been sent, count it toward our TX airtime utilization.
uint32_t xmitMsec = getPacketTime(txp);
airTime->logAirtime(TX_LOG, xmitMsec);
}
}
} else {
// DEBUG_MSG("done with txqueue\n");
@@ -210,6 +212,26 @@ void RadioLibInterface::onNotify(uint32_t notification)
}
}
void RadioLibInterface::setTransmitDelay()
{
MeshPacket *p = txQueue.getFront();
// We want all sending/receiving to be done by our daemon thread.
// We use a delay here because this packet might have been sent in response to a packet we just received.
// So we want to make sure the other side has had a chance to reconfigure its radio.
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
* This assumption is valid because of the offset generated by the radio to account for the noise
* floor.
*/
if (p->rx_snr == 0 && p->rx_rssi == 0) {
startTransmitTimer(true);
} else {
// If there is a SNR, start a timer scaled based on that SNR.
DEBUG_MSG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr);
startTransmitTimerSNR(p->rx_snr);
}
}
void RadioLibInterface::startTransmitTimer(bool withDelay)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
@@ -311,7 +333,7 @@ void RadioLibInterface::handleReceiveInterrupt()
printPacket("Lora RX", mp);
//xmitMsec = getPacketTime(mp);
// xmitMsec = getPacketTime(mp);
airTime->logAirtime(RX_LOG, xmitMsec);
deliverToReceiver(mp);
@@ -334,7 +356,7 @@ void RadioLibInterface::startSend(MeshPacket *txp)
size_t numbytes = beginSending(txp);
int res = iface->startTransmit(radiobuf, numbytes);
if(res != ERR_NONE) {
if (res != ERR_NONE) {
RECORD_CRITICALERROR(CriticalErrorCode_RadioSpiBug);
// This send failed, but make sure to 'complete' it properly

View File

@@ -132,6 +132,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
*/
virtual void startReceive() = 0;
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() = 0;
/** are we actively receiving a packet (only called during receiving state)
* This method is only public to facilitate debugging. Do not call.
*/
@@ -141,18 +144,14 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
virtual bool cancelSending(NodeNum from, PacketId id) override;
private:
/** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing
* the transmit
*
* If the timer was already running, we just wait for that one to occur.
* */
/** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually doing
* the transmit */
void setTransmitDelay();
/** random timer with certain min. and max. settings */
void startTransmitTimer(bool withDelay = true);
/** if we have something waiting to send, start a short scaled timer based on SNR so we can come check for collision before actually doing
* the transmit
*
* If the timer was already running, we just wait for that one to occur.
* */
/** timer scaled to SNR of to be flooded packet */
void startTransmitTimerSNR(float snr);
void handleTransmitInterrupt();

View File

@@ -1,12 +1,15 @@
#include "configuration.h"
#include "Router.h"
#include "Channels.h"
#include "CryptoEngine.h"
#include "NodeDB.h"
#include "RTC.h"
#include "configuration.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "modules/RoutingModule.h"
extern "C" {
#include "mesh/compression/unishox2.h"
}
#if defined(HAS_WIFI) || defined(PORTDUINO)
#include "mqtt/MQTT.h"
@@ -210,29 +213,27 @@ ErrorCode Router::send(MeshPacket *p)
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
#if defined(HAS_WIFI) || defined(PORTDUINO)
//check if we should send decrypted packets to mqtt
// check if we should send decrypted packets to mqtt
//truth table:
// truth table:
/* mqtt_server mqtt_encryption_enabled should_encrypt
* not set 0 1
* not set 1 1
* set 0 0
* set 1 1
*
*
* => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE
*/
*/
bool shouldActuallyEncrypt = true;
if (*radioConfig.preferences.mqtt_server && !radioConfig.preferences.mqtt_encryption_enabled) {
shouldActuallyEncrypt = false;
}
DEBUG_MSG("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt);
//the packet is currently in a decrypted state. send it now if they want decrypted packets
// the packet is currently in a decrypted state. send it now if they want decrypted packets
if (mqtt && !shouldActuallyEncrypt)
mqtt->onSend(*p, chIndex);
#endif
@@ -244,8 +245,8 @@ ErrorCode Router::send(MeshPacket *p)
}
#if defined(HAS_WIFI) || defined(PORTDUINO)
//the packet is now encrypted.
//check if we should send encrypted packets to mqtt
// the packet is now encrypted.
// check if we should send encrypted packets to mqtt
if (mqtt && shouldActuallyEncrypt)
mqtt->onSend(*p, chIndex);
#endif
@@ -276,7 +277,7 @@ bool perhapsDecode(MeshPacket *p)
if (p->which_payloadVariant == MeshPacket_decoded_tag)
return true; // If packet was already decoded just return
//assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
// assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
// Try to find a channel that works with this hash
for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) {
@@ -302,6 +303,14 @@ bool perhapsDecode(MeshPacket *p)
// parsing was successful
p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded
p->channel = chIndex; // change to store the index instead of the hash
// Decompress if needed. jm
if (p->decoded.which_payloadVariant == Data_payload_compressed_tag) {
// Decompress the file
}
printPacket("decoded message", p);
return true;
}
@@ -320,10 +329,56 @@ Routing_Error perhapsEncode(MeshPacket *p)
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
// printPacket("pre encrypt", p); // portnum valid here
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
// Only allow encryption on the text message app.
// TODO: Allow modules to opt into compression.
if (p->decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
char original_payload[Constants_DATA_PAYLOAD_LEN];
memcpy(original_payload, p->decoded.payload.bytes, p->decoded.payload.size);
char compressed_out[Constants_DATA_PAYLOAD_LEN] = {0};
int compressed_len;
// compressed_len = unishox2_compress_simple(original_payload, p->decoded.payload.size, compressed_out);
Serial.print("Original length - ");
Serial.println(p->decoded.payload.size);
Serial.print("Compressed length - ");
Serial.println(compressed_len);
// Serial.println(compressed_out);
// If the compressed length is greater than or equal to the original size, don't use the compressed form
if (compressed_len >= p->decoded.payload.size) {
DEBUG_MSG("Not compressing message. Not enough benefit from doing so.\n");
// Set the uncompressed payload varient anyway. Shouldn't hurt?
p->decoded.which_payloadVariant = Data_payload_tag;
// Otherwise we use the compressor
} else {
DEBUG_MSG("Compressing message.\n");
// Copy the compressed data into the meshpacket
//p->decoded.payload_compressed.size = compressed_len;
//memcpy(p->decoded.payload_compressed.bytes, compressed_out, compressed_len);
//p->decoded.which_payloadVariant = Data_payload_compressed_tag;
}
if (0) {
char decompressed_out[Constants_DATA_PAYLOAD_LEN] = {};
int decompressed_len;
// decompressed_len = unishox2_decompress_simple(compressed_out, compressed_len, decompressed_out);
Serial.print("Decompressed length - ");
Serial.println(decompressed_len);
Serial.println(decompressed_out);
}
}
if (numbytes > MAX_RHPACKETLEN)
return Routing_Error_TOO_LARGE;

View File

@@ -226,6 +226,23 @@ void SX126xInterface<T>::startReceive()
#endif
}
/** Could we send right now (i.e. either not actively receving or transmitting)? */
template<typename T>
bool SX126xInterface<T>::isChannelActive()
{
// check if we can detect a LoRa preamble on the current channel
int16_t result;
setStandby();
result = lora.scanChannel();
if (result == PREAMBLE_DETECTED)
return true;
assert(result != ERR_WRONG_MODEM);
return false;
}
/** Could we send right now (i.e. either not actively receving or transmitting)? */
template<typename T>
bool SX126xInterface<T>::isActivelyReceiving()

View File

@@ -46,6 +46,9 @@ class SX126xInterface : public RadioLibInterface
*/
virtual void enableInterrupt(void (*callback)()) { lora.setDio1Action(callback); }
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() override;
/** are we actively receiving a packet (only called during receiving state) */
virtual bool isActivelyReceiving() override;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,278 @@
/*
* Copyright (C) 2020 Siara Logics (cc)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Arundale Ramanathan
*
*/
/**
* @file unishox2.h
* @author Arundale Ramanathan, James Z. M. Gao
* @brief API for Unishox2 Compression and Decompression
*
* This file describes each function of the Unishox2 API \n
* For finding out how this API can be used in your program, \n
* please see test_unishox2.c.
*/
#ifndef unishox2
#define unishox2
#define UNISHOX_VERSION "2.0" ///< Unicode spec version
/**
* Macro switch to enable/disable output buffer length parameter in low level api \n
* Disabled by default \n
* When this macro is defined, the all the API functions \n
* except the simple API functions accept an additional parameter olen \n
* that enables the developer to pass the size of the output buffer provided \n
* so that the api function may not write beyond that length. \n
* This can be disabled if the developer knows that the buffer provided is sufficient enough \n
* so no additional parameter is passed and the program is faster since additional check \n
* for output length is not performed at each step \n
* The simple api, i.e. unishox2_(de)compress_simple will always omit the buffer length
*/
#ifndef UNISHOX_API_WITH_OUTPUT_LEN
# define UNISHOX_API_WITH_OUTPUT_LEN 0
#endif
/// Upto 8 bits of initial magic bit sequence can be included. Bit count can be specified with UNISHOX_MAGIC_BIT_LEN
#ifndef UNISHOX_MAGIC_BITS
# define UNISHOX_MAGIC_BITS 0xFF
#endif
/// Desired length of Magic bits defined by UNISHOX_MAGIC_BITS
#ifdef UNISHOX_MAGIC_BIT_LEN
# if UNISHOX_MAGIC_BIT_LEN < 0 || 9 <= UNISHOX_MAGIC_BIT_LEN
# error "UNISHOX_MAGIC_BIT_LEN need between [0, 8)"
# endif
#else
# define UNISHOX_MAGIC_BIT_LEN 1
#endif
//enum {USX_ALPHA = 0, USX_SYM, USX_NUM, USX_DICT, USX_DELTA};
/// Default Horizontal codes. When composition of text is know beforehand, the other hcodes in this section can be used to achieve more compression.
#define USX_HCODES_DFLT (const unsigned char[]) {0x00, 0x40, 0x80, 0xC0, 0xE0}
/// Length of each default hcode
#define USX_HCODE_LENS_DFLT (const unsigned char[]) {2, 2, 2, 3, 3}
/// Horizontal codes preset for English Alphabet content only
#define USX_HCODES_ALPHA_ONLY (const unsigned char[]) {0x00, 0x00, 0x00, 0x00, 0x00}
/// Length of each Alpha only hcode
#define USX_HCODE_LENS_ALPHA_ONLY (const unsigned char[]) {0, 0, 0, 0, 0}
/// Horizontal codes preset for Alpha Numeric content only
#define USX_HCODES_ALPHA_NUM_ONLY (const unsigned char[]) {0x00, 0x00, 0x80, 0x00, 0x00}
/// Length of each Alpha numeric hcode
#define USX_HCODE_LENS_ALPHA_NUM_ONLY (const unsigned char[]) {1, 0, 1, 0, 0}
/// Horizontal codes preset for Alpha Numeric and Symbol content only
#define USX_HCODES_ALPHA_NUM_SYM_ONLY (const unsigned char[]) {0x00, 0x80, 0xC0, 0x00, 0x00}
/// Length of each Alpha numeric and symbol hcodes
#define USX_HCODE_LENS_ALPHA_NUM_SYM_ONLY (const unsigned char[]) {1, 2, 2, 0, 0}
/// Horizontal codes preset favouring Alphabet content
#define USX_HCODES_FAVOR_ALPHA (const unsigned char[]) {0x00, 0x80, 0xA0, 0xC0, 0xE0}
/// Length of each hcode favouring Alpha content
#define USX_HCODE_LENS_FAVOR_ALPHA (const unsigned char[]) {1, 3, 3, 3, 3}
/// Horizontal codes preset favouring repeating sequences
#define USX_HCODES_FAVOR_DICT (const unsigned char[]) {0x00, 0x40, 0xC0, 0x80, 0xE0}
/// Length of each hcode favouring repeating sequences
#define USX_HCODE_LENS_FAVOR_DICT (const unsigned char[]) {2, 2, 3, 2, 3}
/// Horizontal codes preset favouring symbols
#define USX_HCODES_FAVOR_SYM (const unsigned char[]) {0x80, 0x00, 0xA0, 0xC0, 0xE0}
/// Length of each hcode favouring symbols
#define USX_HCODE_LENS_FAVOR_SYM (const unsigned char[]) {3, 1, 3, 3, 3}
//#define USX_HCODES_FAVOR_UMLAUT {0x00, 0x40, 0xE0, 0xC0, 0x80}
//#define USX_HCODE_LENS_FAVOR_UMLAUT {2, 2, 3, 3, 2}
/// Horizontal codes preset favouring umlaut letters
#define USX_HCODES_FAVOR_UMLAUT (const unsigned char[]) {0x80, 0xA0, 0xC0, 0xE0, 0x00}
/// Length of each hcode favouring umlaut letters
#define USX_HCODE_LENS_FAVOR_UMLAUT (const unsigned char[]) {3, 3, 3, 3, 1}
/// Horizontal codes preset for no repeating sequences
#define USX_HCODES_NO_DICT (const unsigned char[]) {0x00, 0x40, 0x80, 0x00, 0xC0}
/// Length of each hcode for no repeating sequences
#define USX_HCODE_LENS_NO_DICT (const unsigned char[]) {2, 2, 2, 0, 2}
/// Horizontal codes preset for no Unicode characters
#define USX_HCODES_NO_UNI (const unsigned char[]) {0x00, 0x40, 0x80, 0xC0, 0x00}
/// Length of each hcode for no Unicode characters
#define USX_HCODE_LENS_NO_UNI (const unsigned char[]) {2, 2, 2, 2, 0}
/// Default frequently occuring sequences. When composition of text is know beforehand, the other sequences in this section can be used to achieve more compression.
#define USX_FREQ_SEQ_DFLT (const char *[]) {"\": \"", "\": ", "</", "=\"", "\":\"", "://"}
/// Frequently occuring sequences in text content
#define USX_FREQ_SEQ_TXT (const char *[]) {" the ", " and ", "tion", " with", "ing", "ment"}
/// Frequently occuring sequences in URL content
#define USX_FREQ_SEQ_URL (const char *[]) {"https://", "www.", ".com", "http://", ".org", ".net"}
/// Frequently occuring sequences in JSON content
#define USX_FREQ_SEQ_JSON (const char *[]) {"\": \"", "\": ", "\",", "}}}", "\":\"", "}}"}
/// Frequently occuring sequences in HTML content
#define USX_FREQ_SEQ_HTML (const char *[]) {"</", "=\"", "div", "href", "class", "<p>"}
/// Frequently occuring sequences in XML content
#define USX_FREQ_SEQ_XML (const char *[]) {"</", "=\"", "\">", "<?xml version=\"1.0\"", "xmlns:", "://"}
/// Commonly occuring templates (ISO Date/Time, ISO Date, US Phone number, ISO Time, Unused)
#define USX_TEMPLATES (const char *[]) {"tfff-of-tfTtf:rf:rf.fffZ", "tfff-of-tf", "(fff) fff-ffff", "tf:rf:rf", 0}
/// Default preset parameter set. When composition of text is know beforehand, the other parameter sets in this section can be used to achieve more compression.
#define USX_PSET_DFLT USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for English Alphabet only content
#define USX_PSET_ALPHA_ONLY USX_HCODES_ALPHA_ONLY, USX_HCODE_LENS_ALPHA_ONLY, USX_FREQ_SEQ_TXT, USX_TEMPLATES
/// Preset parameter set for Alpha numeric content
#define USX_PSET_ALPHA_NUM_ONLY USX_HCODES_ALPHA_NUM_ONLY, USX_HCODE_LENS_ALPHA_NUM_ONLY, USX_FREQ_SEQ_TXT, USX_TEMPLATES
/// Preset parameter set for Alpha numeric and symbol content
#define USX_PSET_ALPHA_NUM_SYM_ONLY USX_HCODES_ALPHA_NUM_SYM_ONLY, USX_HCODE_LENS_ALPHA_NUM_SYM_ONLY, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for Alpha numeric symbol content having predominantly text
#define USX_PSET_ALPHA_NUM_SYM_ONLY_TXT USX_HCODES_ALPHA_NUM_SYM_ONLY, USX_HCODE_LENS_ALPHA_NUM_SYM_ONLY, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set favouring Alphabet content
#define USX_PSET_FAVOR_ALPHA USX_HCODES_FAVOR_ALPHA, USX_HCODE_LENS_FAVOR_ALPHA, USX_FREQ_SEQ_TXT, USX_TEMPLATES
/// Preset parameter set favouring repeating sequences
#define USX_PSET_FAVOR_DICT USX_HCODES_FAVOR_DICT, USX_HCODE_LENS_FAVOR_DICT, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set favouring symbols
#define USX_PSET_FAVOR_SYM USX_HCODES_FAVOR_SYM, USX_HCODE_LENS_FAVOR_SYM, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set favouring unlaut letters
#define USX_PSET_FAVOR_UMLAUT USX_HCODES_FAVOR_UMLAUT, USX_HCODE_LENS_FAVOR_UMLAUT, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for when there are no repeating sequences
#define USX_PSET_NO_DICT USX_HCODES_NO_DICT, USX_HCODE_LENS_NO_DICT, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for when there are no unicode symbols
#define USX_PSET_NO_UNI USX_HCODES_NO_UNI, USX_HCODE_LENS_NO_UNI, USX_FREQ_SEQ_DFLT, USX_TEMPLATES
/// Preset parameter set for when there are no unicode symbols favouring text
#define USX_PSET_NO_UNI_FAVOR_TEXT USX_HCODES_NO_UNI, USX_HCODE_LENS_NO_UNI, USX_FREQ_SEQ_TXT, USX_TEMPLATES
/// Preset parameter set favouring URL content
#define USX_PSET_URL USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_URL, USX_TEMPLATES
/// Preset parameter set favouring JSON content
#define USX_PSET_JSON USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_JSON, USX_TEMPLATES
/// Preset parameter set favouring JSON content having no Unicode symbols
#define USX_PSET_JSON_NO_UNI USX_HCODES_NO_UNI, USX_HCODE_LENS_NO_UNI, USX_FREQ_SEQ_JSON, USX_TEMPLATES
/// Preset parameter set favouring XML content
#define USX_PSET_XML USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_XML, USX_TEMPLATES
/// Preset parameter set favouring HTML content
#define USX_PSET_HTML USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_HTML, USX_TEMPLATES
/**
* This structure is used when a string array needs to be compressed.
* This is passed as a parameter to the unishox2_decompress_lines() function
*/
struct us_lnk_lst {
char *data;
struct us_lnk_lst *previous;
};
/**
* This macro is for internal use, but builds upon the macro UNISHOX_API_WITH_OUTPUT_LEN
* When the macro UNISHOX_API_WITH_OUTPUT_LEN is defined, the all the API functions
* except the simple API functions accept an additional parameter olen
* that enables the developer to pass the size of the output buffer provided
* so that the api function may not write beyond that length.
* This can be disabled if the developer knows that the buffer provided is sufficient enough
* so no additional parameter is passed and the program is faster since additional check
* for output length is not performed at each step
*/
#if defined(UNISHOX_API_WITH_OUTPUT_LEN) && UNISHOX_API_WITH_OUTPUT_LEN != 0
# define UNISHOX_API_OUT_AND_LEN(out, olen) out, olen
#else
# define UNISHOX_API_OUT_AND_LEN(out, olen) out
#endif
/**
* Simple API for compressing a string
* @param[in] in Input ASCII / UTF-8 string
* @param[in] len length in bytes
* @param[out] out output buffer - should be large enough to hold compressed output
*/
extern int unishox2_compress_simple(const char *in, int len, char *out);
/**
* Simple API for decompressing a string
* @param[in] in Input compressed bytes (output of unishox2_compress functions)
* @param[in] len length of 'in' in bytes
* @param[out] out output buffer for ASCII / UTF-8 string - should be large enough
*/
extern int unishox2_decompress_simple(const char *in, int len, char *out);
/**
* Comprehensive API for compressing a string
*
* Presets are available for the last four parameters so they can be passed as single parameter. \n
* See USX_PSET_* macros. Example call: \n
* unishox2_compress(in, len, out, olen, USX_PSET_ALPHA_ONLY);
*
* @param[in] in Input ASCII / UTF-8 string
* @param[in] len length in bytes
* @param[out] out output buffer - should be large enough to hold compressed output
* @param[in] olen length of 'out' buffer in bytes. Can be omitted if sufficient buffer is provided
* @param[in] usx_hcodes Horizontal codes (array of bytes). See macro section for samples.
* @param[in] usx_hcode_lens Length of each element in usx_hcodes array
* @param[in] usx_freq_seq Frequently occuring sequences. See USX_FREQ_SEQ_* macros for samples
* @param[in] usx_templates Templates of frequently occuring patterns. See USX_TEMPLATES macro.
*/
extern int unishox2_compress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[],
const char *usx_freq_seq[], const char *usx_templates[]);
/**
* Comprehensive API for de-compressing a string
*
* Presets are available for the last four parameters so they can be passed as single parameter. \n
* See USX_PSET_* macros. Example call: \n
* unishox2_decompress(in, len, out, olen, USX_PSET_ALPHA_ONLY);
*
* @param[in] in Input compressed bytes (output of unishox2_compress functions)
* @param[in] len length of 'in' in bytes
* @param[out] out output buffer - should be large enough to hold de-compressed output
* @param[in] olen length of 'out' buffer in bytes. Can be omitted if sufficient buffer is provided
* @param[in] usx_hcodes Horizontal codes (array of bytes). See macro section for samples.
* @param[in] usx_hcode_lens Length of each element in usx_hcodes array
* @param[in] usx_freq_seq Frequently occuring sequences. See USX_FREQ_SEQ_* macros for samples
* @param[in] usx_templates Templates of frequently occuring patterns. See USX_TEMPLATES macro.
*/
extern int unishox2_decompress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[],
const char *usx_freq_seq[], const char *usx_templates[]);
/**
* More Comprehensive API for compressing array of strings
*
* See unishox2_compress() function for parameter definitions. \n
* This function takes an additional parameter, i.e. 'prev_lines' - the usx_lnk_lst structure \n
* See -g parameter in test_unishox2.c to find out how this can be used. \n
* This function is used when an array of strings need to be compressed \n
* and stored in a compressed array of bytes for use as a constant in other programs \n
* where each element of the array can be decompressed and used at runtime.
*/
extern int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[],
const char *usx_freq_seq[], const char *usx_templates[],
struct us_lnk_lst *prev_lines);
/**
* More Comprehensive API for de-compressing array of strings \n
* This function is not be used in conjuction with unishox2_compress_lines()
*
* See unishox2_decompress() function for parameter definitions. \n
* Typically an array is compressed using unishox2_compress_lines() and \n
* a header (.h) file is generated using the resultant compressed array. \n
* This header file can be used in another program with another decompress \n
* routine which takes this compressed array as parameter and index to be \n
* decompressed.
*/
extern int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[],
const char *usx_freq_seq[], const char *usx_templates[],
struct us_lnk_lst *prev_lines);
#endif

View File

@@ -129,7 +129,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
#define AdminMessage_fields &AdminMessage_msg
/* Maximum encoded size of messages (where known) */
#define AdminMessage_size 610
#define AdminMessage_size 598
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -12,4 +12,8 @@ PB_BIND(DeviceState, DeviceState, 4)
PB_BIND(ChannelFile, ChannelFile, 2)
PB_BIND(OEMStore, OEMStore, 2)

View File

@@ -11,6 +11,17 @@
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Enum definitions */
/* TODO: REPLACE */
typedef enum _ScreenFonts {
/* TODO: REPLACE */
ScreenFonts_FONT_SMALL = 0,
/* TODO: REPLACE */
ScreenFonts_FONT_MEDIUM = 1,
/* TODO: REPLACE */
ScreenFonts_FONT_LARGE = 2
} ScreenFonts;
/* Struct definitions */
/* The on-disk saved channels */
typedef struct _ChannelFile {
@@ -33,7 +44,7 @@ typedef struct _DeviceState {
User owner;
/* TODO: REPLACE */
pb_size_t node_db_count;
NodeInfo node_db[80];
NodeInfo node_db[64];
/* Received packets saved for delivery to the phone */
pb_size_t receive_queue_count;
MeshPacket receive_queue[1];
@@ -53,16 +64,40 @@ typedef struct _DeviceState {
bool did_gps_reset;
} DeviceState;
typedef PB_BYTES_ARRAY_T(2048) OEMStore_oem_icon_bits_t;
/* This can be used for customizing the firmware distribution. If populated,
show a secondary bootup screen with cuatom logo and text for 2.5 seconds. */
typedef struct _OEMStore {
/* The Logo width in Px */
uint32_t oem_icon_width;
/* The Logo height in Px */
uint32_t oem_icon_height;
/* The Logo in xbm bytechar format */
OEMStore_oem_icon_bits_t oem_icon_bits;
/* Use this font for the OEM text. */
ScreenFonts oem_font;
/* Use this font for the OEM text. */
char oem_text[40];
} OEMStore;
/* Helper constants for enums */
#define _ScreenFonts_MIN ScreenFonts_FONT_SMALL
#define _ScreenFonts_MAX ScreenFonts_FONT_LARGE
#define _ScreenFonts_ARRAYSIZE ((ScreenFonts)(ScreenFonts_FONT_LARGE+1))
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define DeviceState_init_default {false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
#define DeviceState_init_default {false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
#define ChannelFile_init_default {0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}}
#define DeviceState_init_zero {false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
#define OEMStore_init_default {0, 0, {0, {0}}, _ScreenFonts_MIN, ""}
#define DeviceState_init_zero {false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
#define ChannelFile_init_zero {0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}}
#define OEMStore_init_zero {0, 0, {0, {0}}, _ScreenFonts_MIN, ""}
/* Field tags (for use in manual encoding/decoding) */
#define ChannelFile_channels_tag 1
@@ -74,6 +109,11 @@ extern "C" {
#define DeviceState_version_tag 8
#define DeviceState_no_save_tag 9
#define DeviceState_did_gps_reset_tag 11
#define OEMStore_oem_icon_width_tag 1
#define OEMStore_oem_icon_height_tag 2
#define OEMStore_oem_icon_bits_tag 3
#define OEMStore_oem_font_tag 4
#define OEMStore_oem_text_tag 5
/* Struct field encoding specification for nanopb */
#define DeviceState_FIELDLIST(X, a) \
@@ -99,16 +139,28 @@ X(a, STATIC, REPEATED, MESSAGE, channels, 1)
#define ChannelFile_DEFAULT NULL
#define ChannelFile_channels_MSGTYPE Channel
#define OEMStore_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, oem_icon_width, 1) \
X(a, STATIC, SINGULAR, UINT32, oem_icon_height, 2) \
X(a, STATIC, SINGULAR, BYTES, oem_icon_bits, 3) \
X(a, STATIC, SINGULAR, UENUM, oem_font, 4) \
X(a, STATIC, SINGULAR, STRING, oem_text, 5)
#define OEMStore_CALLBACK NULL
#define OEMStore_DEFAULT NULL
extern const pb_msgdesc_t DeviceState_msg;
extern const pb_msgdesc_t ChannelFile_msg;
extern const pb_msgdesc_t OEMStore_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define DeviceState_fields &DeviceState_msg
#define ChannelFile_fields &ChannelFile_msg
#define OEMStore_fields &OEMStore_msg
/* Maximum encoded size of messages (where known) */
#define ChannelFile_size 832
#define DeviceState_size 23903
#define DeviceState_size 19327
#define OEMStore_size 2106
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -61,6 +61,10 @@ typedef enum _HardwareModel {
HardwareModel_DIY_V1 = 39,
/* RAK WisBlock ESP32 core: https://docs.rakwireless.com/Product-Categories/WisBlock/RAK11200/Overview/ */
HardwareModel_RAK11200 = 40,
/* B&Q Consulting Nano Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:nano */
HardwareModel_NANO_G1 = 41,
/* nRF52840 Dongle : https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle/ */
HardwareModel_NRF52840_PCA10059 = 42,
/* 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;
@@ -496,6 +500,7 @@ typedef struct _User {
} User;
typedef PB_BYTES_ARRAY_T(237) Data_payload_t;
typedef PB_BYTES_ARRAY_T(237) Data_payload_compressed_t;
/* (Formerly called SubPacket)
The payload portion fo a packet, this is the actual bytes that are sent
inside a radio packet (because from/to are broken out by the comms library) */
@@ -503,30 +508,34 @@ typedef struct _Data {
/* Formerly named typ and of type Type */
PortNum portnum;
/* TODO: REPLACE */
Data_payload_t payload;
pb_size_t which_payloadVariant;
union {
Data_payload_t payload;
Data_payload_compressed_t payload_compressed;
};
/* TODO: REPLACE */
bool want_response;
/* Not normally used, but for testing a sender can request that recipient
responds in kind (i.e. if it received a position, it should unicast back it's position).
Note: that if you set this on a broadcast you will receive many replies. */
bool want_response;
uint32_t dest;
/* The address of the destination node.
This field is is filled in by the mesh radio device software, application
layer software should never need it.
RouteDiscovery messages _must_ populate this.
Other message types might need to if they are doing multihop routing. */
uint32_t dest;
uint32_t source;
/* The address of the original sender for this message.
This field should _only_ be populated for reliable multihop packets (to keep
packets small). */
uint32_t source;
uint32_t request_id;
/* Only used in routing or response messages.
Indicates the original message ID that this message is reporting failure on. (formerly called original_id) */
uint32_t request_id;
/* If set, this message is intened to be a reply to a previously sent message with the defined id. */
uint32_t reply_id;
/* If set, this message is intened to be a reply to a previously sent message with the defined id. */
uint32_t emoji;
/* Defaults to false. If true, then what is in the payload should be treated as an emoji like giving
a message a heart or poop emoji. */
uint32_t emoji;
/* Location structure */
bool has_location;
Location location;
} Data;
@@ -734,7 +743,7 @@ extern "C" {
#define User_init_default {"", "", "", {0}, _HardwareModel_MIN, 0, _Team_MIN, 0, 0, 0}
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define Routing_init_default {0, {RouteDiscovery_init_default}}
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, Location_init_default}
#define Data_init_default {_PortNum_MIN, 0, {{0, {0}}}, 0, 0, 0, 0, 0, 0, false, Location_init_default}
#define Location_init_default {0, 0, 0, 0, 0}
#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN}
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0, false, DeviceMetrics_init_default}
@@ -747,7 +756,7 @@ extern "C" {
#define User_init_zero {"", "", "", {0}, _HardwareModel_MIN, 0, _Team_MIN, 0, 0, 0}
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define Routing_init_zero {0, {RouteDiscovery_init_zero}}
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, Location_init_zero}
#define Data_init_zero {_PortNum_MIN, 0, {{0, {0}}}, 0, 0, 0, 0, 0, 0, false, Location_init_zero}
#define Location_init_zero {0, 0, 0, 0, 0}
#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN}
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0, false, DeviceMetrics_init_zero}
@@ -821,6 +830,7 @@ extern "C" {
#define User_ant_azimuth_tag 12
#define Data_portnum_tag 1
#define Data_payload_tag 2
#define Data_payload_compressed_tag 10
#define Data_want_response_tag 3
#define Data_dest_tag 4
#define Data_source_tag 5
@@ -919,14 +929,15 @@ X(a, STATIC, ONEOF, UENUM, (variant,error_reason,error_reason), 3)
#define Data_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, portnum, 1) \
X(a, STATIC, SINGULAR, BYTES, payload, 2) \
X(a, STATIC, ONEOF, BYTES, (payloadVariant,payload,payload), 2) \
X(a, STATIC, SINGULAR, BOOL, want_response, 3) \
X(a, STATIC, SINGULAR, FIXED32, dest, 4) \
X(a, STATIC, SINGULAR, FIXED32, source, 5) \
X(a, STATIC, SINGULAR, FIXED32, request_id, 6) \
X(a, STATIC, SINGULAR, FIXED32, reply_id, 7) \
X(a, STATIC, SINGULAR, FIXED32, emoji, 8) \
X(a, STATIC, OPTIONAL, MESSAGE, location, 9)
X(a, STATIC, OPTIONAL, MESSAGE, location, 9) \
X(a, STATIC, ONEOF, BYTES, (payloadVariant,payload_compressed,payload_compressed), 10)
#define Data_CALLBACK NULL
#define Data_DEFAULT NULL
#define Data_location_MSGTYPE Location

View File

@@ -210,7 +210,12 @@ typedef enum _RadioConfig_UserPreferences_Serial_Baud {
/* TODO: REPLACE */
RadioConfig_UserPreferences_Serial_Baud_BAUD_576000 = 10,
/* TODO: REPLACE */
RadioConfig_UserPreferences_Serial_Baud_BAUD_921600 = 11
RadioConfig_UserPreferences_Serial_Baud_BAUD_921600 = 11,
/* TODO: REPLACE */
RadioConfig_UserPreferences_Serial_Baud_BAUD_110 = 12,
RadioConfig_UserPreferences_Serial_Baud_BAUD_300 = 13,
RadioConfig_UserPreferences_Serial_Baud_BAUD_600 = 14,
RadioConfig_UserPreferences_Serial_Baud_BAUD_1200 = 15
} RadioConfig_UserPreferences_Serial_Baud;
/* Defines the device's role on the Mesh network
@@ -260,11 +265,9 @@ typedef enum _RadioConfig_UserPreferences_TelemetrySensorType {
/* Struct definitions */
typedef struct _RadioConfig_UserPreferences {
uint32_t position_broadcast_secs;
uint32_t send_owner_interval;
uint32_t wait_bluetooth_secs;
uint32_t screen_on_secs;
uint32_t phone_timeout_secs;
uint32_t phone_sds_timeout_sec;
uint32_t mesh_sds_timeout_secs;
uint32_t sds_secs;
uint32_t ls_secs;
@@ -383,8 +386,8 @@ typedef struct _RadioConfig {
#define _InputEventChar_ARRAYSIZE ((InputEventChar)(InputEventChar_KEY_BACK+1))
#define _RadioConfig_UserPreferences_Serial_Baud_MIN RadioConfig_UserPreferences_Serial_Baud_BAUD_Default
#define _RadioConfig_UserPreferences_Serial_Baud_MAX RadioConfig_UserPreferences_Serial_Baud_BAUD_921600
#define _RadioConfig_UserPreferences_Serial_Baud_ARRAYSIZE ((RadioConfig_UserPreferences_Serial_Baud)(RadioConfig_UserPreferences_Serial_Baud_BAUD_921600+1))
#define _RadioConfig_UserPreferences_Serial_Baud_MAX RadioConfig_UserPreferences_Serial_Baud_BAUD_1200
#define _RadioConfig_UserPreferences_Serial_Baud_ARRAYSIZE ((RadioConfig_UserPreferences_Serial_Baud)(RadioConfig_UserPreferences_Serial_Baud_BAUD_1200+1))
#define _RadioConfig_UserPreferences_Serial_Mode_MIN RadioConfig_UserPreferences_Serial_Mode_MODE_Default
#define _RadioConfig_UserPreferences_Serial_Mode_MAX RadioConfig_UserPreferences_Serial_Mode_MODE_PROTO
@@ -401,17 +404,15 @@ extern "C" {
/* Initializer values for message structs */
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _Role_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_Serial_Mode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_TelemetrySensorType_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, 0, 0, 0, 0, _InputEventChar_MIN, _InputEventChar_MIN, _InputEventChar_MIN, 0, 0, "", 0, 0, 0, _RadioConfig_UserPreferences_Serial_Baud_MIN, 0}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _Role_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_Serial_Mode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_TelemetrySensorType_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, 0, 0, 0, 0, _InputEventChar_MIN, _InputEventChar_MIN, _InputEventChar_MIN, 0, 0, "", 0, 0, 0, _RadioConfig_UserPreferences_Serial_Baud_MIN, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _Role_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_Serial_Mode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_TelemetrySensorType_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, 0, 0, 0, 0, _InputEventChar_MIN, _InputEventChar_MIN, _InputEventChar_MIN, 0, 0, "", 0, 0, 0, _RadioConfig_UserPreferences_Serial_Baud_MIN, 0}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _Role_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_Serial_Mode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_TelemetrySensorType_MIN, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, 0, 0, 0, 0, _InputEventChar_MIN, _InputEventChar_MIN, _InputEventChar_MIN, 0, 0, "", 0, 0, 0, _RadioConfig_UserPreferences_Serial_Baud_MIN, 0}
/* Field tags (for use in manual encoding/decoding) */
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
#define RadioConfig_UserPreferences_send_owner_interval_tag 2
#define RadioConfig_UserPreferences_wait_bluetooth_secs_tag 4
#define RadioConfig_UserPreferences_screen_on_secs_tag 5
#define RadioConfig_UserPreferences_phone_timeout_secs_tag 6
#define RadioConfig_UserPreferences_phone_sds_timeout_sec_tag 7
#define RadioConfig_UserPreferences_mesh_sds_timeout_secs_tag 8
#define RadioConfig_UserPreferences_sds_secs_tag 9
#define RadioConfig_UserPreferences_ls_secs_tag 10
@@ -502,11 +503,9 @@ X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1)
#define RadioConfig_UserPreferences_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \
X(a, STATIC, SINGULAR, UINT32, send_owner_interval, 2) \
X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \
X(a, STATIC, SINGULAR, UINT32, screen_on_secs, 5) \
X(a, STATIC, SINGULAR, UINT32, phone_timeout_secs, 6) \
X(a, STATIC, SINGULAR, UINT32, phone_sds_timeout_sec, 7) \
X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 8) \
X(a, STATIC, SINGULAR, UINT32, sds_secs, 9) \
X(a, STATIC, SINGULAR, UINT32, ls_secs, 10) \
@@ -597,8 +596,8 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
/* Maximum encoded size of messages (where known) */
#define RadioConfig_UserPreferences_size 604
#define RadioConfig_size 607
#define RadioConfig_UserPreferences_size 592
#define RadioConfig_size 595
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -40,10 +40,10 @@ typedef struct _EnvironmentMetrics {
/* Types of Measurements the telemetry module is equipped to handle */
typedef struct _Telemetry {
/* This is usually not sent over the mesh (to save space), but it is sent
from the phone so that the local device can set its RTC If it is sent over
the mesh (because there are devices on the mesh without GPS), it will only
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
/* This is usually not sent over the mesh (to save space), but it is sent
from the phone so that the local device can set its RTC If it is sent over
the mesh (because there are devices on the mesh without GPS), it will only
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
seconds since 1970 */
uint32_t time;
/* Key native device metrics such as battery level */

View File

@@ -8,10 +8,11 @@
#include "mesh/http/WiFiAPClient.h"
#include "power.h"
#include "sleep.h"
#include <FSCommon.h>
#include <HTTPBodyParser.hpp>
#include <HTTPMultipartBodyParser.hpp>
#include <HTTPURLEncodedBodyParser.hpp>
#include <FSCommon.h>
#include <json11.hpp>
#ifndef NO_ESP32
#include "esp_task_wdt.h"
@@ -46,11 +47,9 @@ using namespace httpsserver;
#include <WiFiClientSecure.h>
HTTPClient httpClient;
// needed for ESP32-targz
#define DEST_FS_USES_LITTLEFS
#define ESP_ARDUINO_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
#define ESP_ARDUINO_VERSION ESP_ARDUINO_VERSION_VAL(1, 0, 4)
#include <ESP32-targz.h>
// We need to specify some content-type mapping, so the resources get delivered with the
// right content type and are displayed correctly in the browser
@@ -62,57 +61,13 @@ char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"}
{".svg", "image/svg+xml"}, {"", ""}};
// const char *tarURL = "https://www.casler.org/temp/meshtastic-web.tar";
const char *tarURL = "https://api-production-871d.up.railway.app/mirror/webui";
const char *certificate = NULL; // change this as needed, leave as is for no TLS check (yolo security)
// const char *tarURL = "https://api-production-871d.up.railway.app/mirror/webui";
// const char *certificate = NULL; // change this as needed, leave as is for no TLS check (yolo security)
// Our API to handle messages to and from the radio.
HttpAPI webAPI;
WiFiClient *getTarHTTPClientPtr(WiFiClientSecure *client, const char *url, const char *cert = NULL)
{
if (cert == NULL) {
// New versions don't have setInsecure
// client->setInsecure();
} else {
client->setCACert(cert);
}
const char *UserAgent = "ESP32-HTTP-GzUpdater-Client";
httpClient.setReuse(true); // handle 301 redirects gracefully
httpClient.setUserAgent(UserAgent);
httpClient.setConnectTimeout(10000); // 10s timeout = 10000
if (!httpClient.begin(*client, url)) {
log_e("Can't open url %s", url);
return nullptr;
}
const char *headerKeys[] = {"location", "redirect", "Content-Type", "Content-Length", "Content-Disposition"};
const size_t numberOfHeaders = 5;
httpClient.collectHeaders(headerKeys, numberOfHeaders);
int httpCode = httpClient.GET();
// file found at server
if (httpCode == HTTP_CODE_FOUND || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String newlocation = "";
String headerLocation = httpClient.header("location");
String headerRedirect = httpClient.header("redirect");
if (headerLocation != "") {
newlocation = headerLocation;
Serial.printf("302 (location): %s => %s\n", url, headerLocation.c_str());
} else if (headerRedirect != "") {
Serial.printf("301 (redirect): %s => %s\n", url, headerLocation.c_str());
newlocation = headerRedirect;
}
httpClient.end();
if (newlocation != "") {
log_w("Found 302/301 location header: %s", newlocation.c_str());
return getTarHTTPClientPtr(client, newlocation.c_str(), cert);
} else {
log_e("Empty redirect !!");
return nullptr;
}
}
if (httpCode != 200)
return nullptr;
return httpClient.getStreamPtr();
}
void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
{
@@ -130,9 +85,9 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
ResourceNode *nodeAdmin = new ResourceNode("/admin", "GET", &handleAdmin);
ResourceNode *nodeAdminSettings = new ResourceNode("/admin/settings", "GET", &handleAdminSettings);
ResourceNode *nodeAdminSettingsApply = new ResourceNode("/admin/settings/apply", "POST", &handleAdminSettingsApply);
ResourceNode *nodeAdminFs = new ResourceNode("/admin/fs", "GET", &handleFs);
ResourceNode *nodeUpdateFs = new ResourceNode("/admin/fs/update", "POST", &handleUpdateFs);
ResourceNode *nodeDeleteFs = new ResourceNode("/admin/fs/delete", "GET", &handleDeleteFsContent);
// ResourceNode *nodeAdminFs = new ResourceNode("/admin/fs", "GET", &handleFs);
// ResourceNode *nodeUpdateFs = new ResourceNode("/admin/fs/update", "POST", &handleUpdateFs);
// ResourceNode *nodeDeleteFs = new ResourceNode("/admin/fs/delete", "GET", &handleDeleteFsContent);
ResourceNode *nodeRestart = new ResourceNode("/restart", "POST", &handleRestart);
ResourceNode *nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload);
@@ -159,10 +114,10 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
secureServer->registerNode(nodeJsonFsBrowseStatic);
secureServer->registerNode(nodeJsonDelete);
secureServer->registerNode(nodeJsonReport);
secureServer->registerNode(nodeUpdateFs);
secureServer->registerNode(nodeDeleteFs);
// secureServer->registerNode(nodeUpdateFs);
// secureServer->registerNode(nodeDeleteFs);
secureServer->registerNode(nodeAdmin);
secureServer->registerNode(nodeAdminFs);
// secureServer->registerNode(nodeAdminFs);
secureServer->registerNode(nodeAdminSettings);
secureServer->registerNode(nodeAdminSettingsApply);
secureServer->registerNode(nodeRoot); // This has to be last
@@ -180,10 +135,10 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
insecureServer->registerNode(nodeJsonFsBrowseStatic);
insecureServer->registerNode(nodeJsonDelete);
insecureServer->registerNode(nodeJsonReport);
insecureServer->registerNode(nodeUpdateFs);
insecureServer->registerNode(nodeDeleteFs);
// insecureServer->registerNode(nodeUpdateFs);
// insecureServer->registerNode(nodeDeleteFs);
insecureServer->registerNode(nodeAdmin);
insecureServer->registerNode(nodeAdminFs);
// insecureServer->registerNode(nodeAdminFs);
insecureServer->registerNode(nodeAdminSettings);
insecureServer->registerNode(nodeAdminSettingsApply);
insecureServer->registerNode(nodeRoot); // This has to be last
@@ -272,8 +227,6 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
DEBUG_MSG("webAPI handleAPIv1ToRadio\n");
}
bool firstFile = 1;
void htmlDeleteDir(const char * dirname)
{
File root = FSCom.open(dirname);
@@ -301,70 +254,72 @@ void htmlDeleteDir(const char * dirname)
root.close();
}
void htmlListDir(HTTPResponse *res, const char * dirname, uint8_t levels)
std::vector<std::map<char *, char *>>* htmlListDir(std::vector<std::map<char *, char *>> *fileList, const char *dirname, uint8_t levels)
{
File root = FSCom.open(dirname);
if(!root){
return;
return NULL;
}
if(!root.isDirectory()){
return;
return NULL;
}
// iterate over the file list
File file = root.openNextFile();
while(file){
if(file.isDirectory() && !String(file.name()).endsWith(".")) {
if(levels){
htmlListDir(res, file.name(), levels -1);
htmlListDir(fileList, file.name(), levels -1);
}
} else {
if (firstFile) {
firstFile = 0;
} else {
res->println(",");
}
res->println("{");
} else {
std::map<char*, char*> thisFileMap;
thisFileMap[strdup("size")] = strdup(String(file.size()).c_str());
thisFileMap[strdup("name")] = strdup(String(file.name()).substring(1).c_str());
if (String(file.name()).substring(1).endsWith(".gz")) {
String modifiedFile = String(file.name()).substring(1);
modifiedFile.remove((modifiedFile.length() - 3), 3);
res->print("\"nameModified\": \"" + modifiedFile + "\",");
res->print("\"name\": \"" + String(file.name()).substring(1) + "\",");
} else {
res->print("\"name\": \"" + String(file.name()).substring(1) + "\",");
thisFileMap[strdup("nameModified")] = strdup(modifiedFile.c_str());
}
res->print("\"size\": " + String(file.size()));
res->print("}");
fileList->push_back(thisFileMap);
}
file.close();
file = root.openNextFile();
}
root.close();
return fileList;
}
void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "application/json");
res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "GET");
res->println("{");
res->println("\"data\": {");
res->print("\"files\": [");
htmlListDir(res, "/", 10);
res->print("],");
res->print("\"filesystem\" : {");
res->print("\"total\" : " + String(FSCom.totalBytes()) + ",");
res->print("\"used\" : " + String(FSCom.usedBytes()) + ",");
res->print("\"free\" : " + String(FSCom.totalBytes() - FSCom.usedBytes()));
res->println("}");
res->println("},");
res->println("\"status\": \"ok\"");
res->println("}");
}
using namespace json11;
auto fileList = htmlListDir(new std::vector<std::map<char *, char *>>(), "/", 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()},
};
Json jsonObjInner = Json::object{{"files", Json(*fileList)},
{"filesystem", filesystemObj}
};
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}};
// serialize and write it to the stream
std::string jsonStr = jsonObjOuter.dump();
res->print(jsonStr.c_str());
}
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
{
using namespace json11;
ResourceParameters *params = req->getParams();
std::string paramValDelete;
@@ -375,15 +330,15 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
std::string pathDelete = "/" + paramValDelete;
if (FSCom.remove(pathDelete.c_str())) {
Serial.println(pathDelete.c_str());
res->println("{");
res->println("\"status\": \"ok\"");
res->println("}");
Json jsonObjOuter = Json::object{{"status", "ok"}};
std::string jsonStr = jsonObjOuter.dump();
res->print(jsonStr.c_str());
return;
} else {
Serial.println(pathDelete.c_str());
res->println("{");
res->println("\"status\": \"Error\"");
res->println("}");
Json jsonObjOuter = Json::object{{"status", "Error"}};
std::string jsonStr = jsonObjOuter.dump();
res->print(jsonStr.c_str());
return;
}
}
@@ -600,6 +555,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
void handleReport(HTTPRequest *req, HTTPResponse *res)
{
using namespace json11;
ResourceParameters *params = req->getParams();
std::string content;
@@ -618,104 +574,89 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
res->println("<pre>");
}
res->println("{");
res->println("\"data\": {");
res->println("\"airtime\": {");
// data->airtime->tx_log
std::vector<String> txLogValues;
uint32_t *logArray;
res->print("\"tx_log\": [");
logArray = airTime->airtimeReport(TX_LOG);
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
uint32_t tmp;
tmp = *(logArray + i);
res->printf("%d", tmp);
if (i != airTime->getPeriodsToLog() - 1) {
res->print(", ");
}
txLogValues.push_back(String(tmp));
}
res->println("],");
res->print("\"rx_log\": [");
// data->airtime->rx_log
std::vector<String> rxLogValues;
logArray = airTime->airtimeReport(RX_LOG);
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
uint32_t tmp;
tmp = *(logArray + i);
res->printf("%d", tmp);
if (i != airTime->getPeriodsToLog() - 1) {
res->print(", ");
}
rxLogValues.push_back(String(tmp));
}
res->println("],");
res->print("\"rx_all_log\": [");
// data->airtime->rx_all_log
std::vector<String> rxAllLogValues;
logArray = airTime->airtimeReport(RX_ALL_LOG);
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
uint32_t tmp;
tmp = *(logArray + i);
res->printf("%d", tmp);
if (i != airTime->getPeriodsToLog() - 1) {
res->print(", ");
}
rxAllLogValues.push_back(String(tmp));
}
res->println("],");
res->printf("\"channel_utilization\": %3.2f%,\n", airTime->channelUtilizationPercent());
res->printf("\"utilization_tx\": %3.2f%,\n", airTime->utilizationTXPercent());
res->printf("\"seconds_since_boot\": %u,\n", airTime->getSecondsSinceBoot());
res->printf("\"seconds_per_period\": %u,\n", airTime->getSecondsPerPeriod());
res->printf("\"periods_to_log\": %u\n", airTime->getPeriodsToLog());
res->println("},");
res->println("\"wifi\": {");
res->println("\"rssi\": " + String(WiFi.RSSI()) + ",");
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->wifi
String ipStr;
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
res->println("\"ip\": \"" + String(WiFi.softAPIP().toString().c_str()) + "\"");
ipStr = String(WiFi.softAPIP().toString());
} else {
res->println("\"ip\": \"" + String(WiFi.localIP().toString().c_str()) + "\"");
ipStr = String(WiFi.localIP().toString());
}
Json jsonObjWifi = Json::object{
{"rssi", String(WiFi.RSSI())},
{"ip", ipStr.c_str()}
};
res->println("},");
// 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()}};
res->println("\"memory\": {");
res->printf("\"heap_total\": %d,\n", ESP.getHeapSize());
res->printf("\"heap_free\": %d,\n", ESP.getFreeHeap());
res->printf("\"psram_total\": %d,\n", ESP.getPsramSize());
res->printf("\"psram_free\": %d,\n", ESP.getFreePsram());
res->println("\"fs_total\" : " + String(FSCom.totalBytes()) + ",");
res->println("\"fs_used\" : " + String(FSCom.usedBytes()) + ",");
res->println("\"fs_free\" : " + String(FSCom.totalBytes() - FSCom.usedBytes()));
res->println("},");
// 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())}};
res->println("\"power\": {");
res->printf("\"battery_percent\": %u,\n", powerStatus->getBatteryChargePercent());
res->printf("\"battery_voltage_mv\": %u,\n", powerStatus->getBatteryVoltageMv());
res->printf("\"has_battery\": %s,\n", BoolToString(powerStatus->getHasBattery()));
res->printf("\"has_usb\": %s,\n", BoolToString(powerStatus->getHasUSB()));
res->printf("\"is_charging\": %s\n", BoolToString(powerStatus->getIsCharging()));
res->println("},");
// data->device
Json jsonObjDevice = Json::object{{"reboot_counter", Json(int(myNodeInfo.reboot_count))}};
res->println("\"device\": {");
res->printf("\"reboot_counter\": %d\n", myNodeInfo.reboot_count);
res->println("},");
// data->radio
Json jsonObjRadio = Json::object{{"frequency", Json(RadioLibInterface::instance->getFreq())},
{"lora_channel", Json(int(RadioLibInterface::instance->getChannelNum()))}};
res->println("\"radio\": {");
res->printf("\"frequecy\": %f,\n", RadioLibInterface::instance->getFreq());
res->printf("\"lora_channel\": %d\n", RadioLibInterface::instance->getChannelNum());
res->println("}");
// collect data to inner data object
Json jsonObjInner = Json::object{{"airtime", jsonObjAirtime}, {"wifi", jsonObjWifi}, {"memory", jsonObjMemory},
{"power", jsonObjPower}, {"device", jsonObjDevice}, {"radio", jsonObjRadio}};
res->println("},");
res->println("\"status\": \"ok\"");
res->println("}");
// create json output structure
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}};
// serialize and write it to the stream
std::string jsonStr = jsonObjOuter.dump();
res->print(jsonStr.c_str());
}
/*
@@ -740,86 +681,6 @@ void handleHotspot(HTTPRequest *req, HTTPResponse *res)
res->println("<meta http-equiv=\"refresh\" content=\"0;url=/\" />\n");
}
void handleUpdateFs(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "text/html");
res->setHeader("Access-Control-Allow-Origin", "*");
// res->setHeader("Access-Control-Allow-Methods", "POST");
res->println("<h1>Meshtastic</h1>\n");
res->println("Downloading Meshtastic Web Content...");
WiFiClientSecure *client = new WiFiClientSecure;
Stream *streamptr = getTarHTTPClientPtr(client, tarURL, certificate);
delay(5); // Let other network operations run
if (streamptr != nullptr) {
DEBUG_MSG("Connection to content server ... success!\n");
DEBUG_MSG("Deleting files from /static : \n");
htmlDeleteDir("/static");
delay(5); // Let other network operations run
TarUnpacker *TARUnpacker = new TarUnpacker();
TARUnpacker->haltOnError(false); // stop on fail (manual restart/reset required)
TARUnpacker->setTarVerify(false); // true = enables health checks but slows down the overall process
TARUnpacker->setupFSCallbacks(targzTotalBytesFn, targzFreeBytesFn); // prevent the partition from exploding, recommended
TARUnpacker->setLoggerCallback(BaseUnpacker::targzPrintLoggerCallback); // gz log verbosity
TARUnpacker->setTarProgressCallback(
BaseUnpacker::defaultProgressCallback); // prints the untarring progress for each individual file
TARUnpacker->setTarStatusProgressCallback(
BaseUnpacker::defaultTarStatusProgressCallback); // print the filenames as they're expanded
TARUnpacker->setTarMessageCallback(BaseUnpacker::targzPrintLoggerCallback); // tar log verbosity
String contentLengthStr = httpClient.header("Content-Length");
contentLengthStr.trim();
int64_t streamSize = -1;
if (contentLengthStr != "") {
streamSize = atoi(contentLengthStr.c_str());
Serial.printf("Stream size %d\n", streamSize);
res->printf("Stream size %d<br><br>\n", streamSize);
}
if (!TARUnpacker->tarStreamExpander(streamptr, streamSize, FSCom, "/static")) {
res->printf("tarStreamExpander failed with return code #%d\n", TARUnpacker->tarGzGetError());
Serial.printf("tarStreamExpander failed with return code #%d\n", TARUnpacker->tarGzGetError());
// Close the connection on error and free up memory
client->stop();
return;
} else {
/*
// print leftover bytes if any (probably zero-fill from the server)
while (httpClient.connected()) {
size_t streamSize = streamptr->available();
if (streamSize) {
Serial.printf("%02x ", streamptr->read());
} else
break;
}
*/
}
} else {
res->printf("Failed to establish http connection\n");
Serial.println("Failed to establish http connection");
return;
// Close the connection on error and free up memory
client->stop();
}
res->println("Done! Restarting the device. <a href=/>Click this in 10 seconds</a>");
/*
* This is a work around for a bug where we run out of memory.
* TODO: Fixme!
*/
// ESP.restart();
webServerThread->requestRestart = (millis() / 1000) + 5;
}
void handleDeleteFsContent(HTTPRequest *req, HTTPResponse *res)
{
@@ -912,6 +773,8 @@ 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");
@@ -938,28 +801,25 @@ void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
screen->blink();
}
res->println("{");
res->println("\"status\": \"ok\"");
res->println("}");
Json jsonObjOuter = Json::object{{"status", "ok"}};
std::string jsonStr = jsonObjOuter.dump();
res->print(jsonStr.c_str());
}
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");
// res->setHeader("Content-Type", "text/html");
int n = WiFi.scanNetworks();
res->println("{");
res->println("\"data\": {");
if (n == 0) {
// No networks found.
res->println("\"networks\": []");
} else {
res->println("\"networks\": [");
// build list of network objects
std::vector<Json> networkObjs;
if (n > 0) {
for (int i = 0; i < n; ++i) {
char ssidArray[50];
String ssidString = String(WiFi.SSID(i));
@@ -967,19 +827,20 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
ssidString.toCharArray(ssidArray, 50);
if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) {
res->printf("{\"ssid\": \"%s\",\"rssi\": %d}", ssidArray, WiFi.RSSI(i));
if (i != n - 1) {
res->printf(",");
}
Json thisNetwork = Json::object{{"ssid", ssidArray}, {"rssi", WiFi.RSSI(i)}};
networkObjs.push_back(thisNetwork);
}
// Yield some cpu cycles to IP stack.
// This is important in case the list is large and it takes us time to return
// to the main loop.
yield();
}
res->println("]");
}
res->println("},");
res->println("\"status\": \"ok\"");
res->println("}");
// build output structure
Json jsonObjOuter = Json::object{{"data", networkObjs}, {"status", "ok"}};
// serialize and write it to the stream
std::string jsonStr = jsonObjOuter.dump();
res->print(jsonStr.c_str());
}

View File

@@ -10,10 +10,13 @@
#include "target_specific.h"
#include <DNSServer.h>
#include <ESPmDNS.h>
#include <NTPClient.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#ifndef DISABLE_NTP
#include <NTPClient.h>
#endif
using namespace concurrency;
static void WiFiEvent(WiFiEvent_t event);
@@ -23,7 +26,10 @@ DNSServer dnsServer;
// NTP
WiFiUDP ntpUDP;
#ifndef DISABLE_NTP
NTPClient timeClient(ntpUDP, "0.pool.ntp.org");
#endif
uint8_t wifiDisconnectReason = 0;
@@ -67,13 +73,13 @@ static int32_t reconnectWiFi()
DEBUG_MSG("... Reconnecting to WiFi access point\n");
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw);
// Starting timeClient;
}
}
//if (*wifiName) {
#ifndef DISABLE_NTP
// if (*wifiName) {
if (WiFi.isConnected()) {
DEBUG_MSG("Updating NTP time\n");
if (timeClient.update()) {
@@ -89,6 +95,7 @@ static int32_t reconnectWiFi()
DEBUG_MSG("NTP Update failed\n");
}
}
#endif
return 30 * 1000; // every 30 seconds
}
@@ -155,9 +162,11 @@ static void onNetworkConnected()
MDNS.addService("https", "tcp", 443);
}
#ifndef DISABLE_NTP
DEBUG_MSG("Starting NTP time client\n");
timeClient.begin();
timeClient.setUpdateInterval(60*60); // Update once an hour
timeClient.setUpdateInterval(60 * 60); // Update once an hour
#endif
initWebServer();
initApiServer();

View File

@@ -118,7 +118,7 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies)
p->priority = MeshPacket_Priority_BACKGROUND;
prevPacketId = p->id;
service.sendToMesh(p);
service.sendToMesh(p, RX_SRC_LOCAL, true);
}
int32_t PositionModule::runOnce()

View File

@@ -27,7 +27,7 @@ int32_t DeviceTelemetryModule::runOnce()
bool DeviceTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemetry *t)
{
if (t->which_variant == Telemetry_device_metrics_tag) {
String sender = getSenderName(mp);
const char *sender = getSenderShortName(mp);
DEBUG_MSG("-----------------------------------------\n");
DEBUG_MSG("Device Telemetry: Received data from %s\n", sender);
@@ -44,19 +44,6 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemet
return false; // Let others look at this message also if they want
}
String DeviceTelemetryModule::getSenderName(const MeshPacket &mp)
{
String sender;
auto node = nodeDB.getNode(getFrom(&mp));
if (node) {
sender = node->user.short_name;
} else {
sender = "UNK";
}
return sender;
}
bool DeviceTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies)
{
Telemetry t;

View File

@@ -27,7 +27,6 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu
bool sendOurTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
private:
String getSenderName(const MeshPacket &mp);
bool firstTime = 1;
const MeshPacket *lastMeasurementPacket;
};

View File

@@ -149,19 +149,6 @@ int32_t EnvironmentTelemetryModule::runOnce()
#endif
}
String GetSenderName(const MeshPacket &mp)
{
String sender;
auto node = nodeDB.getNode(getFrom(&mp));
if (node) {
sender = node->user.short_name;
} else {
sender = "UNK";
}
return sender;
}
uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp)
{
uint32_t now = getTime();
@@ -198,7 +185,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
Telemetry lastMeasurement;
uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket);
String lastSender = GetSenderName(*lastMeasurementPacket);
const char *lastSender = getSenderShortName(*lastMeasurementPacket);
auto &p = lastMeasurementPacket->decoded;
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, Telemetry_fields, &lastMeasurement)) {
@@ -213,16 +200,16 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
if (radioConfig.preferences.telemetry_module_environment_display_fahrenheit) {
last_temp = String(CelsiusToFahrenheit(lastMeasurement.variant.environment_metrics.temperature), 0) + "°F";
}
display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + lastSender + "(" + String(agoSecs) + "s)");
display->drawString(x, y += fontHeight(FONT_SMALL) - 2,"Temp/Hum: " + last_temp + " / " + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%");
display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
display->drawString(x, y += fontHeight(FONT_SMALL) - 2, "Temp/Hum: " + last_temp + " / " + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%");
if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0)
display->drawString(x, y += fontHeight(FONT_SMALL),"Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA");
display->drawString(x, y += fontHeight(FONT_SMALL), "Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA");
}
bool EnvironmentTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemetry *t)
{
if (t->which_variant == Telemetry_environment_metrics_tag) {
String sender = GetSenderName(mp);
const char *sender = getSenderShortName(mp);
DEBUG_MSG("-----------------------------------------\n");
DEBUG_MSG("Environment Telemetry: Received data from %s\n", sender);

View File

@@ -93,6 +93,18 @@ int32_t SerialModule::runOnce()
if (radioConfig.preferences.serial_module_baud == RadioConfig_UserPreferences_Serial_Baud_BAUD_Default) {
baud = 38400;
} else if (radioConfig.preferences.serial_module_baud == RadioConfig_UserPreferences_Serial_Baud_BAUD_110) {
baud = 110;
} else if (radioConfig.preferences.serial_module_baud == RadioConfig_UserPreferences_Serial_Baud_BAUD_300) {
baud = 300;
} else if (radioConfig.preferences.serial_module_baud == RadioConfig_UserPreferences_Serial_Baud_BAUD_600) {
baud = 600;
} else if (radioConfig.preferences.serial_module_baud == RadioConfig_UserPreferences_Serial_Baud_BAUD_1200) {
baud = 1200;
} else if (radioConfig.preferences.serial_module_baud == RadioConfig_UserPreferences_Serial_Baud_BAUD_2400) {
baud = 2400;

View File

@@ -290,8 +290,8 @@ String MQTT::downstreamPacketToJson(MeshPacket *mp)
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Telemetry_msg,
&scratch)) {
decoded = &scratch;
if (decoded->which_variant == Telemetry_environment_metrics_tag) {
decoded = &scratch;
msgPayload = Json::object{
{"temperature", decoded->variant.environment_metrics.temperature},
{"relative_humidity", decoded->variant.environment_metrics.relative_humidity},

View File

@@ -1,12 +1,9 @@
#include "configuration.h"
#include "CryptoEngine.h"
#include "ocrypto_aes_ctr.h"
#include <Adafruit_nRFCrypto.h>
#include "aes-256/tiny-aes.h"
class NRF52CryptoEngine : public CryptoEngine
{
public:
NRF52CryptoEngine() {}
@@ -19,29 +16,47 @@ class NRF52CryptoEngine : public CryptoEngine
*/
virtual void encrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override
{
// DEBUG_MSG("NRF52 encrypt!\n");
if (key.length > 0) {
ocrypto_aes_ctr_ctx ctx;
// DEBUG_MSG("NRF52 encrypt!\n");
if (key.length > 16) {
AES_ctx ctx;
initNonce(fromNode, packetId);
ocrypto_aes_ctr_init(&ctx, key.bytes, key.length, nonce);
ocrypto_aes_ctr_encrypt(&ctx, bytes, bytes, numBytes);
AES_init_ctx_iv(&ctx, key.bytes, nonce);
AES_CTR_xcrypt_buffer(&ctx, bytes, numBytes);
} else if (key.length > 0) {
nRFCrypto.begin();
nRFCrypto_AES ctx;
uint8_t myLen = ctx.blockLen(numBytes);
char encBuf[myLen] = {0};
memcpy(encBuf, bytes, numBytes);
initNonce(fromNode, packetId);
ctx.begin();
ctx.Process(encBuf, numBytes, nonce, key.bytes, key.length, (char*)bytes, ctx.encryptFlag, ctx.ctrMode);
ctx.end();
nRFCrypto.end();
}
}
virtual void decrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override
{
// DEBUG_MSG("NRF52 decrypt!\n");
if (key.length > 0) {
ocrypto_aes_ctr_ctx ctx;
// DEBUG_MSG("NRF52 decrypt!\n");
if (key.length > 16) {
AES_ctx ctx;
initNonce(fromNode, packetId);
ocrypto_aes_ctr_init(&ctx, key.bytes, key.length, nonce);
ocrypto_aes_ctr_decrypt(&ctx, bytes, bytes, numBytes);
AES_init_ctx_iv(&ctx, key.bytes, nonce);
AES_CTR_xcrypt_buffer(&ctx, bytes, numBytes);
} else if (key.length > 0) {
nRFCrypto.begin();
nRFCrypto_AES ctx;
uint8_t myLen = ctx.blockLen(numBytes);
char decBuf[myLen] = {0};
memcpy(decBuf, bytes, numBytes);
initNonce(fromNode, packetId);
ctx.begin();
ctx.Process(decBuf, numBytes, nonce, key.bytes, key.length, (char*)bytes, ctx.decryptFlag, ctx.ctrMode);
ctx.end();
nRFCrypto.end();
}
}

View File

@@ -0,0 +1,229 @@
/*
AES-256 Software Implementation
based on https://github.com/kokke/tiny-AES-C/ which is in public domain
NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
You should pad the end of the string with zeros if this is not the case.
For AES192/256 the key size is proportionally larger.
*/
#include <string.h>
#include "tiny-aes.h"
#define Nb 4
#define Nk 8
#define Nr 14
typedef uint8_t state_t[4][4];
static const uint8_t sbox[256] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
static const uint8_t Rcon[11] = {
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
#define getSBoxValue(num) (sbox[(num)])
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
{
uint8_t tempa[4];
for (unsigned i = 0; i < Nk; ++i)
{
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
}
for (unsigned i = Nk; i < Nb * (Nr + 1); ++i)
{
unsigned k = (i - 1) * 4;
tempa[0]=RoundKey[k + 0];
tempa[1]=RoundKey[k + 1];
tempa[2]=RoundKey[k + 2];
tempa[3]=RoundKey[k + 3];
if (i % Nk == 0)
{
const uint8_t u8tmp = tempa[0];
tempa[0] = tempa[1];
tempa[1] = tempa[2];
tempa[2] = tempa[3];
tempa[3] = u8tmp;
tempa[0] = getSBoxValue(tempa[0]);
tempa[1] = getSBoxValue(tempa[1]);
tempa[2] = getSBoxValue(tempa[2]);
tempa[3] = getSBoxValue(tempa[3]);
tempa[0] = tempa[0] ^ Rcon[i/Nk];
}
if (i % Nk == 4)
{
tempa[0] = getSBoxValue(tempa[0]);
tempa[1] = getSBoxValue(tempa[1]);
tempa[2] = getSBoxValue(tempa[2]);
tempa[3] = getSBoxValue(tempa[3]);
}
unsigned j = i * 4; k=(i - Nk) * 4;
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
}
}
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
{
KeyExpansion(ctx->RoundKey, key);
}
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
{
KeyExpansion(ctx->RoundKey, key);
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
}
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
{
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
}
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
{
for (uint8_t i = 0; i < 4; ++i)
{
for (uint8_t j = 0; j < 4; ++j)
{
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
}
}
}
static void SubBytes(state_t* state)
{
for (uint8_t i = 0; i < 4; ++i)
{
for (uint8_t j = 0; j < 4; ++j)
{
(*state)[j][i] = getSBoxValue((*state)[j][i]);
}
}
}
static void ShiftRows(state_t* state)
{
uint8_t temp = (*state)[0][1];
(*state)[0][1] = (*state)[1][1];
(*state)[1][1] = (*state)[2][1];
(*state)[2][1] = (*state)[3][1];
(*state)[3][1] = temp;
temp = (*state)[0][2];
(*state)[0][2] = (*state)[2][2];
(*state)[2][2] = temp;
temp = (*state)[1][2];
(*state)[1][2] = (*state)[3][2];
(*state)[3][2] = temp;
temp = (*state)[0][3];
(*state)[0][3] = (*state)[3][3];
(*state)[3][3] = (*state)[2][3];
(*state)[2][3] = (*state)[1][3];
(*state)[1][3] = temp;
}
static uint8_t xtime(uint8_t x)
{
return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
}
static void MixColumns(state_t* state)
{
for (uint8_t i = 0; i < 4; ++i)
{
uint8_t t = (*state)[i][0];
uint8_t Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
uint8_t Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ;
Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ;
Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ;
Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ;
}
}
#define Multiply(x, y) \
( ((y & 1) * x) ^ \
((y>>1 & 1) * xtime(x)) ^ \
((y>>2 & 1) * xtime(xtime(x))) ^ \
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
static void Cipher(state_t* state, const uint8_t* RoundKey)
{
uint8_t round = 0;
AddRoundKey(0, state, RoundKey);
for (round = 1; ; ++round)
{
SubBytes(state);
ShiftRows(state);
if (round == Nr) {
break;
}
MixColumns(state);
AddRoundKey(round, state, RoundKey);
}
AddRoundKey(Nr, state, RoundKey);
}
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
{
uint8_t buffer[AES_BLOCKLEN];
size_t i;
int bi;
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
{
if (bi == AES_BLOCKLEN)
{
memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
Cipher((state_t*)buffer,ctx->RoundKey);
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
{
if (ctx->Iv[bi] == 255)
{
ctx->Iv[bi] = 0;
continue;
}
ctx->Iv[bi] += 1;
break;
}
bi = 0;
}
buf[i] = (buf[i] ^ buffer[bi]);
}
}

View File

@@ -0,0 +1,23 @@
#ifndef _TINY_AES_H_
#define _TINY_AES_H_
#include <stdint.h>
#include <stddef.h>
#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only
// #define AES_KEYLEN 32
#define AES_keyExpSize 240
struct AES_ctx
{
uint8_t RoundKey[AES_keyExpSize];
uint8_t Iv[AES_BLOCKLEN];
};
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
#endif // _TINY_AES_H_

View File

@@ -5,6 +5,7 @@
#include <ble_gap.h>
#include <memory.h>
#include <stdio.h>
#include <Adafruit_nRFCrypto.h>
// #include <Adafruit_USBD_Device.h>
#include "NRF52Bluetooth.h"
@@ -32,8 +33,8 @@ void __attribute__((noreturn)) __assert_func(const char *file, int line, const c
{
DEBUG_MSG("assert failed %s: %d, %s, test=%s\n", file, line, func, failedexpr);
// debugger_break(); FIXME doesn't work, possibly not for segger
while (1)
; // FIXME, reboot!
// Reboot cpu
NVIC_SystemReset();
}
void getMacAddr(uint8_t *dmac)
@@ -145,13 +146,15 @@ void nrf52Setup()
#endif
// Init random seed
// FIXME - use this to get random numbers
// #include "nrf_rng.h"
// uint32_t r;
// ble_controller_rand_vector_get_blocking(&r, sizeof(r));
// randomSeed(r);
DEBUG_MSG("FIXME, call randomSeed\n");
// ::printf("TESTING PRINTF\n");
union seedParts {
uint32_t seed32;
uint8_t seed8[4];
} seed;
nRFCrypto.begin();
nRFCrypto.Random.generate(seed.seed8, sizeof(seed.seed8));
DEBUG_MSG("Setting random seed %u\n", seed.seed32);
randomSeed(seed.seed32);
nRFCrypto.end();
}
void cpuDeepSleep(uint64_t msecToWake)
@@ -193,4 +196,4 @@ void clearBonds() {
nrf52Bluetooth->setup();
}
nrf52Bluetooth->clearBonds();
}
}

View File

@@ -7,9 +7,11 @@
void powerCommandsCheck()
{
if (rebootAtMsec && millis() > rebootAtMsec) {
DEBUG_MSG("Rebooting\n");
#ifndef NO_ESP32
DEBUG_MSG("Rebooting for update\n");
ESP.restart();
#elif NRF52_SERIES
NVIC_SystemReset();
#else
DEBUG_MSG("FIXME implement reboot for this platform");
#endif

View File

@@ -0,0 +1,9 @@
[env:pca10059_diy_eink]
extends = nrf52840_base
board = nordic_pca10059
build_flags = ${nrf52840_base.build_flags} -Ivariants/Dongle_nRF52840-pca10059-v1 -D NORDIC_PCA10059
src_filter = ${nrf52_base.src_filter} +<../variants/Dongle_nRF52840-pca10059-v1>
lib_deps =
${nrf52840_base.lib_deps}
https://github.com/ZinggJM/GxEPD2.git
debug_tool = jlink

View File

@@ -0,0 +1,180 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _VARIANT_NORDIC_PCA10059_
#define _VARIANT_NORDIC_PCA10059_
#define PCA10059
/** Master clock frequency */
#define VARIANT_MCK (64000000ul)
#define USE_LFXO // Board uses 32khz crystal for LF
// define USE_LFRC // Board uses RC for LF
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "WVariant.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Number of pins defined in PinDescription array
#define PINS_COUNT (48)
#define NUM_DIGITAL_PINS (48)
#define NUM_ANALOG_INPUTS (6)
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define PIN_LED1 (0 + 12) // Blue LED P1.12
#define PIN_LED2 (0 + 6) // Built in Green P0.06
//Green Built in LED1
//#define PIN_LED1 (0 + 6) // LED1 P1.15
//RGB NeoPixel LED2
//#define PIN_LED1 (0 + 8) Red
//#define PIN_LED1 (32 + 9) Green
//#define PIN_LED1 (0 + 12) Blue
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1
#define LED_BLUE PIN_LED2
#define LED_STATE_ON 0 // State when LED is litted
/*
* Buttons
*/
#define PIN_BUTTON1 (32 + 6) // BTN_DN P1.06 Built in button
/*
* Analog pins
*/
#define PIN_A0 (-1)
static const uint8_t A0 = PIN_A0;
#define ADC_RESOLUTION 14
// Other pins
#define PIN_AREF (-1) // AREF Not yet used
static const uint8_t AREF = PIN_AREF;
/*
* Serial interfaces
*/
#define PIN_SERIAL1_RX (-1)
#define PIN_SERIAL1_TX (-1)
// Connected to Jlink CDC
#define PIN_SERIAL2_RX (-1)
#define PIN_SERIAL2_TX (-1)
/*
* SPI Interfaces
*/
#define SPI_INTERFACES_COUNT 2
#define PIN_SPI_MISO (0 + 17) // MISO P0.17
#define PIN_SPI_MOSI (0 + 15) // MOSI P0.15
#define PIN_SPI_SCK (0 + 13) // SCK P0.13
#define PIN_SPI1_MISO (-1) //
#define PIN_SPI1_MOSI (10) // EPD_MOSI P0.10
#define PIN_SPI1_SCK (9) // EPD_SCLK P0.09
static const uint8_t SS = (0 + 31); // LORA_CS P0.31
static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;
/*
* eink display pins
*/
//#define PIN_EINK_EN (-1)
#define PIN_EINK_EN (0 + 6) // Turn on the Green built in LED
#define PIN_EINK_CS (32) // EPD_CS
#define PIN_EINK_BUSY (20) // EPD_BUSY
#define PIN_EINK_DC (24) // EPD_D/C
#define PIN_EINK_RES (-1) // Not Connected P0.22 available
#define PIN_EINK_SCLK (9) // EPD_SCLK
#define PIN_EINK_MOSI (10) // EPD_MOSI
#define HAS_EINK
/*
* Wire Interfaces
*/
#define WIRE_INTERFACES_COUNT 1
#define PIN_WIRE_SDA (32 + 4) // SDA
#define PIN_WIRE_SCL (32 + 7) // SCL
// NiceRF 868 LoRa module
#define USE_SX1262
#define SX126X_CS (0 + 31) // LORA_CS P0.31
#define SX126X_DIO1 (0 + 29) // DIO1 P0.29
#define SX126X_BUSY (0 + 2) // LORA_BUSY P0.02
#define SX126X_RESET (32 + 15) // LORA_RESET P1.15
#define SX126X_TXEN (-1) // TXEN P1.13 NiceRF 868 dont use
#define SX126X_RXEN (-1) // RXEN P1.10 NiceRF 868 dont use
#define SX126X_E22
#define PIN_GPS_EN (-1)
#define PIN_GPS_PPS (-1) // Pulse per second input from the GPS
#define GPS_RX_PIN PIN_SERIAL1_RX
#define GPS_TX_PIN PIN_SERIAL1_TX
// Battery
// The battery sense is hooked to pin A0 (5)
#define BATTERY_PIN PIN_A0
// and has 12 bit resolution
#define BATTERY_SENSE_RESOLUTION_BITS 12
#define BATTERY_SENSE_RESOLUTION 4096.0
// Definition of milliVolt per LSB => 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
#define VBAT_MV_PER_LSB (0.73242188F)
// Voltage divider value => 1.5M + 1M voltage divider on VBAT = (1.5M / (1M + 1.5M))
#define VBAT_DIVIDER (0.4F)
// Compensation factor for the VBAT divider
#define VBAT_DIVIDER_COMP (1.73)
// Fixed calculation of milliVolt from compensation value
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER VBAT_DIVIDER_COMP //REAL_VBAT_MV_PER_LSB
#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x)
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------------
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif

View File

@@ -1,20 +0,0 @@
; The very slick RAK wireless RAK 4631 / 4630 board
[env:rak4631_5005]
extends = nrf52840_base
board = wiscore_rak4631
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board -D RAK_BASE_5005
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board>
debug_tool = jlink
[env:rak4631_19003]
extends = nrf52840_base
board = wiscore_rak4631
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board -D RAK_BASE_19003
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board>
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

View File

@@ -1,9 +0,0 @@
[env:rak4631_5005_eink]
extends = nrf52840_base
board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_E-Paper_Board -D RAK_BASE_5005
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_E-Paper_Board>
lib_deps =
${nrf52840_base.lib_deps}
https://github.com/ZinggJM/GxEPD2.git
debug_tool = jlink

View File

@@ -0,0 +1,8 @@
; The 1.0 release of the nano-g1 board
[env:nano-g1]
extends = esp32_base
board = ttgo-t-beam
lib_deps =
${esp32_base.lib_deps}
build_flags =
${esp32_base.build_flags} -D NANO_G1 -I variants/nano-g1

View File

@@ -0,0 +1,30 @@
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#define I2C_SDA 21
#define I2C_SCL 22
#define BUTTON_PIN 36 // The middle button GPIO on the Nano G1
//#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.
// 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_SX1262
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23
#define LORA_DIO1 33 // SX1262 IRQ
#define LORA_DIO2 32 // SX1262 BUSY
#define LORA_DIO3 // Not connected on PCB
#ifdef USE_SX1262
#define SX126X_CS RF95_NSS // FIXME - we really should define LORA_CS instead
#define SX126X_DIO1 LORA_DIO1
#define SX126X_BUSY LORA_DIO2
#define SX126X_RESET LORA_RESET
#define SX126X_E22 // Not really an E22
// Internally the module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
// code)
#endif

View File

@@ -0,0 +1,12 @@
; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmare for 5005/19003, with or without OLED RAK 1921
[env:rak4631]
extends = nrf52840_base
board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631
src_filter = ${nrf52_base.src_filter} +<../variants/rak4631>
lib_deps =
${nrf52840_base.lib_deps}
melopero/Melopero RV3028@^1.1.0
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

View File

@@ -59,10 +59,8 @@ extern "C" {
* Buttons
*/
#ifdef RAK_BASE_5005
#define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion
#define BUTTON_NEED_PULLUP
#endif
#define PIN_BUTTON2 12
#define PIN_BUTTON3 24
#define PIN_BUTTON4 25
@@ -110,17 +108,39 @@ static const uint8_t AREF = PIN_AREF;
/*
* SPI Interfaces
*/
#define SPI_INTERFACES_COUNT 1
#define SPI_INTERFACES_COUNT 2
#define PIN_SPI_MISO (45)
#define PIN_SPI_MOSI (44)
#define PIN_SPI_SCK (43)
#define PIN_SPI1_MISO (29) // (0 + 29)
#define PIN_SPI1_MOSI (30) // (0 + 30)
#define PIN_SPI1_SCK (3) // (0 + 3)
static const uint8_t SS = 42;
static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;
/*
* eink display pins
*/
#define PIN_EINK_EN (0 + 2) // (0 + 2) Note: this is really just backlight power
#define PIN_EINK_CS (0 + 26)
#define PIN_EINK_BUSY (0 + 4)
#define PIN_EINK_DC (0 + 17)
#define PIN_EINK_RES (-1)
#define PIN_EINK_SCLK (0 + 3)
#define PIN_EINK_MOSI (0 + 30) // also called SDI
// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
//#define PIN_EINK_PWR_ON (-1)
// #define HAS_EINK
/*
* Wire Interfaces
*/
@@ -175,10 +195,11 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_GPS_EN (34)
#define PIN_GPS_PPS (17) // Pulse per second input from the GPS
#ifdef RAK_BASE_5005
#define GPS_RX_PIN PIN_SERIAL1_RX
#define GPS_TX_PIN PIN_SERIAL1_TX
#endif
// RAK12002 RTC Module
#define RV3028_RTC (uint8_t) 0b1010010
// Battery
// The battery sense is hooked to pin A0 (5)

View File

@@ -0,0 +1,13 @@
; The very slick RAK wireless RAK 4631 / 4630 board - Firmware for 5005 with the RAK 14000 ePaper
[env:rak4631_eink]
extends = nrf52840_base
board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631_epaper -D RAK_4631
src_filter = ${nrf52_base.src_filter} +<../variants/rak4631_epaper>
lib_deps =
${nrf52840_base.lib_deps}
https://github.com/ZinggJM/GxEPD2.git
melopero/Melopero RV3028@^1.1.0
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

View File

@@ -0,0 +1,46 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "variant.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
#include "nrf.h"
const uint32_t g_ADigitalPinMap[] =
{
// P0
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
// P1
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47};
void initVariant()
{
// LED1 & LED2
pinMode(PIN_LED1, OUTPUT);
ledOff(PIN_LED1);
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
}

View File

@@ -2,6 +2,7 @@
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@@ -58,10 +59,8 @@ extern "C" {
* Buttons
*/
#ifdef RAK_BASE_5005
#define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion
#define BUTTON_NEED_PULLUP
#endif
#define PIN_BUTTON2 12
#define PIN_BUTTON3 24
#define PIN_BUTTON4 25
@@ -196,10 +195,11 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_GPS_EN (34)
#define PIN_GPS_PPS (17) // Pulse per second input from the GPS
#ifdef RAK_BASE_5005
#define GPS_RX_PIN PIN_SERIAL1_RX
#define GPS_TX_PIN PIN_SERIAL1_TX
#endif
// RAK12002 RTC Module
#define RV3028_RTC (uint8_t) 0b1010010
// Battery
// The battery sense is hooked to pin A0 (5)

View File

@@ -22,7 +22,5 @@
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#define LORA_RESET 23

View File

@@ -1,4 +1,4 @@
[VERSION]
major = 1
minor = 3
build = 5
build = 10