Compare commits

...

303 Commits

Author SHA1 Message Date
Ben Meadors
8d288d5a3c Only on pull request 2024-09-30 19:26:35 -05:00
Ben Meadors
dc55d7dd98 Trunk it 2024-09-30 18:07:11 -05:00
TheMalkavien
553514e3b7 Fix #4911 : Partially rework some code to remove warnings about potential non-aligned memory accesses (#4912)
* * Adding the -Wcast-align compilation flag for
  the rp2040.

* * Some rework to use a struct to access radio data
* Buffer will not be accessed by arithmetic pointer anymore

* * Remplace arithmetic pointer to avoid Warning

* * Avoid 2 little artitmetic pointer

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-30 17:56:29 -05:00
github-actions[bot]
1dace9a508 [create-pull-request] automated change (#4917)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-09-30 17:35:35 -05:00
Jonathan Bennett
dd587419c7 Regenerate public key on boot, to avoid accidental mismatch. (#4916)
* Regenerate public key on boot, to avoid accidental mismatch.

* Fix ifdefs
2024-09-30 17:06:31 -05:00
Thomas Göttgens
bce7d73cc6 Merge pull request #4915 from meshtastic/radiolib-701
Radiolib 702
2024-09-30 21:55:14 +02:00
Thomas Göttgens
810a79668c 7.0.2 dropped 2024-09-30 21:54:00 +02:00
Thomas Göttgens
51ee6c11ea Merge branch 'radiolib-701' of github.com:meshtastic/firmware into radiolib-701 2024-09-30 21:53:31 +02:00
Thomas Göttgens
cb06ab10da Merge pull request #4913 from meshtastic/radiolib-701
Welp it's 7.0.2 now but the branch is still open :-)
2024-09-30 21:12:59 +02:00
Thomas Göttgens
199566a996 let's see if this works 2024-09-30 21:11:48 +02:00
Thomas Göttgens
5fcad1d8c5 Welp it's 7.0.2 now but the branch is still open :-) 2024-09-30 18:15:48 +02:00
Thomas Göttgens
a5bcf48240 Welp it's 7.0.2 now but the branch is still open :-) 2024-09-30 18:12:35 +02:00
Ben Meadors
8ad89ba724 Allow for better target level Radiolib exclude plumbing (#4906)
* WIP

* LR11x0

* Anothern

* =1
2024-09-30 05:14:22 -05:00
Thomas Göttgens
fd6e8613c6 Merge pull request #4908 from scruplelesswizard/fix-artifact-comments
Fix duplicate PR comments
2024-09-30 11:55:35 +02:00
Jason Murray
b529099f90 Update main_matrix.yml 2024-09-29 20:08:23 -07:00
Thomas Göttgens
3896009e55 Merge pull request #4905 from meshtastic/radiolib-701
Update radiolib to 7.0.1
2024-09-29 23:32:47 +02:00
KodinLanewave
6f506cead5 Update INA3221 to 1.0.1 (#4877)
Added new release with compiler error fixes for INA3221 library - updating dependencies so new release will be included

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-29 16:17:43 -05:00
GUVWAF
3492c9aa99 Construct StoreForwardModule for Portduino as well (#4903)
* Construct StoreForwardModule for Portduino as well

* Remove duplicate variables
2024-09-29 16:17:23 -05:00
Thomas Göttgens
19f45d282f Update radiolib to 7.0.1 2024-09-29 23:12:20 +02:00
Michael Gjelsø
d73cbf14d5 Get accelerometerThread running from AdminModule. (#4886) 2024-09-29 11:49:16 -05:00
dahanc
d41d4c930e When importing config, keep Bluetooth on and defer rebooting until co… (#4898)
* When importing config, keep Bluetooth on and defer rebooting until config is committed

* One more place that was prematurely disabling Bluetooth

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-29 07:30:10 -05:00
Ben Meadors
403e5c304e Fix: Not being able to stop Ext. Notification nagging for screenless devices (#4899)
* Move logic up to button thread for screen-less devices

* Comment doesn't apply

* Fiddy

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2024-09-29 07:29:53 -05:00
Ben Meadors
dcb2707d94 Return queue status on rate limit throttling (#4901) 2024-09-29 07:28:20 -05:00
Thomas Göttgens
2e935fd943 why is this different than github docs? 2024-09-29 14:03:22 +02:00
Thomas Göttgens
88af23319c Aha! 2024-09-29 14:00:36 +02:00
Thomas Göttgens
42a3301188 Update main_matrix.yml 2024-09-29 13:58:07 +02:00
Thomas Göttgens
57b8b55fc5 Merge pull request #4900 from meshtastic/caveman99-patch-1
runner debug
2024-09-29 13:55:00 +02:00
Thomas Göttgens
d0440f3cac don't interfere with the trunk check 2024-09-29 13:54:46 +02:00
Thomas Göttgens
ef2035a60c runner debug 2024-09-29 13:52:47 +02:00
Thomas Göttgens
fa29386eb7 Update main_matrix.yml 2024-09-29 12:40:17 +02:00
Jason Murray
7e0665a5cd comment on PR with artifact link (#4896) 2024-09-29 05:01:20 -05:00
github-actions[bot]
233962104c [create-pull-request] automated change (#4897)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-09-28 19:12:10 -05:00
Ben Meadors
a70d5ee9d8 Temporarily remove native AGAIN due to gather-artifacts failure 2024-09-28 15:49:37 -05:00
Thomas Göttgens
a542d41ac7 rats, missed one 2024-09-28 21:59:13 +02:00
Thomas Göttgens
9513c68544 Update main_matrix.yml 2024-09-28 20:37:38 +02:00
Thomas Göttgens
448afb8345 Add C6 Target 2024-09-28 20:37:07 +02:00
Thomas Göttgens
22ecbcb046 Create build_esp32_c6.yml 2024-09-28 20:35:48 +02:00
Thomas Göttgens
7963ca6171 Merge pull request #4869 from meshtastic/t3s3-1121
Support T3S3 LR1121 variant
2024-09-28 20:13:26 +02:00
Ben Meadors
6a355616c7 Another extra 2024-09-28 13:06:01 -05:00
Ben Meadors
ec23189407 Making some board levels extra for uncommon hardware 2024-09-28 13:04:50 -05:00
Thomas Göttgens
479b0856b4 use rfswitch definition and update radiolib 2024-09-28 19:07:11 +02:00
Thomas Göttgens
7289f36600 Merge branch 'master' into t3s3-1121 2024-09-28 17:51:21 +02:00
Thomas Göttgens
ef1f0cb074 Merge pull request #4895 from meshtastic/4884-unset-rx
Don't process RX when region unset
2024-09-28 17:50:29 +02:00
Thomas Göttgens
1e8d089c4e yolo! 2024-09-28 16:40:00 +02:00
Thomas Göttgens
06dab4fa13 Don't process RX when region unset 2024-09-28 16:27:38 +02:00
GUVWAF
12efedec42 Potential fix for bad Rx performance on T1000-E (#4885)
* Potential fix for bad Rx performance on T1000-E

* validate and refactor RF switching, eliminate godmode

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2024-09-28 09:24:13 -05:00
Thomas Göttgens
e530ceb566 Merge pull request #4692 from meshtastic/esp32-c6
First stab at ESP32-C6 support for TLora-C6
2024-09-28 14:05:42 +02:00
Thomas Göttgens
da346159f7 fix overzealous pin definitions 2024-09-28 14:01:42 +02:00
Thomas Göttgens
c650e7d273 finish TLora C6 Support, without bluetooth for now 2024-09-28 13:42:32 +02:00
Thomas Göttgens
f3213a5b2f Merge branch 'master' into esp32-c6 2024-09-28 13:39:55 +02:00
Thomas Göttgens
1dc0cc0d05 Merge pull request #4894 from meshtastic/create-pull-request/patch
Update protobufs and classes
2024-09-28 13:39:18 +02:00
caveman99
f28f5e07b7 [create-pull-request] automated change 2024-09-28 11:38:10 +00:00
Thomas Göttgens
62c306a14b Merge branch 'master' into esp32-c6 2024-09-28 12:33:50 +02:00
Thomas Göttgens
5a2c58197b Merge pull request #4891 from meshtastic/store-n-forward
First stab at enabling store and forward for Native
2024-09-28 12:09:53 +02:00
Thomas Göttgens
cc101f9cd2 run the full suite when run on master 2024-09-28 12:07:05 +02:00
Thomas Göttgens
016e1005df Merge branch 'master' into t3s3-1121 2024-09-28 11:37:42 +02:00
Jonathan Bennett
6e1aa52723 More store-n-forward on native 2024-09-28 11:37:27 +02:00
Jonathan Bennett
5ff265c196 First stab at enabling store and forward for Native 2024-09-28 11:37:27 +02:00
Thomas Göttgens
1f08401070 Merge pull request #4892 from dahanc/master
Only log "Setting DIO2 as RF switch" when doing so and fix battery level
2024-09-28 11:36:54 +02:00
Thomas Göttgens
d1d6bfe693 Merge pull request #4890 from meshtastic/guard-remotehardware
Remove remote hardware from firmware release
2024-09-28 11:36:27 +02:00
Thomas Göttgens
a39280e9df Merge pull request #4893 from meshtastic/softSleep
Only check hardsleep threshold if GPS softsleep is supported
2024-09-28 11:35:57 +02:00
GUVWAF
48fa9f2242 Only check threshold if GPS softsleep is supported 2024-09-28 09:34:37 +02:00
David Huang
7f59cb54ef Instead of having LipoBatteryLevel forward requests to AnalogBatteryLevel if there's no Lipo sensor, just have lipoInit return false. The forwarding didn't work because it never called analogInit. 2024-09-27 23:35:57 -05:00
David Huang
36a66df923 Don't log "Setting DIO2 as RF switch" unless we're actually going to do it. Also, if there's an error setting DIO2, log the error code. 2024-09-27 21:53:13 -05:00
Ben Meadors
8efc15f4d9 Ignore seen phoneapi packets (#4888)
* Ignore PhoneAPI packet if it's been seen

* ignoramus

* Also keep track of the last 20 packet IDs

* Fill

* Make this match the nimble one

* Add the log too

* Ignore zero ID packets

* Remove message entirely

* TRunkt
2024-09-27 20:09:53 -05:00
Ben Meadors
884e3f2e35 Remove remote hardware from release 2024-09-27 20:03:51 -05:00
Ken Piper
0e0811eccd Implement GPIO pin allowlist (#4882) 2024-09-27 19:31:05 -05:00
Jonathan Bennett
fd1b68513a Add sx126x_ant_sw for Native (#4887)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-27 19:29:44 -05:00
Thomas Göttgens
2798946176 Merge branch 'master' into t3s3-1121 2024-09-27 22:59:06 +02:00
Thomas Göttgens
4ee1ae429b Merge branch 'master' into esp32-c6 2024-09-27 22:58:46 +02:00
Thomas Göttgens
482361b252 Fix CAD IRQ setting
credited to @GUVWAF
2024-09-27 22:56:42 +02:00
Thomas Göttgens
cb1cf055b1 Merge branch 'master' into esp32-c6 2024-09-27 22:51:29 +02:00
Thomas Göttgens
6c2e60d415 Merge branch 'master' into t3s3-1121 2024-09-27 22:22:42 +02:00
Jonathan Bennett
ef223b1195 use delete[] to avoid leaking memory (#4883) 2024-09-27 14:55:55 -05:00
Thomas Göttgens
ae14ca7870 the name is somewhat misleading 2024-09-27 10:42:27 +02:00
Thomas Göttgens
747046d335 nope 2024-09-27 10:37:15 +02:00
Thomas Göttgens
e02a7d1c68 test if quick is working at all 2024-09-27 10:36:00 +02:00
Thomas Göttgens
bdb998c763 pick either setup or setup-quick as valid 2024-09-27 10:33:16 +02:00
Thomas Göttgens
c35d780236 only randominze for at least 3 elements 2024-09-27 10:27:57 +02:00
Thomas Göttgens
39febad630 only sample a few builds for CI runs 2024-09-27 10:25:37 +02:00
Thomas Göttgens
40932ea06c update ci builder to include a 'quick' command line option that only outputs 3 random devices or check targets 2024-09-27 10:21:34 +02:00
Thomas Göttgens
f37b88b55e Merge pull request #4880 from meshtastic/radiolib-crc
Update radiolib, fixes CRC bug on SX127x and improves LR11xx support
2024-09-27 10:19:06 +02:00
Thomas Göttgens
743fc2e812 Update radiolib, fixes CRC bug on SX127x and improves LR11xx support 2024-09-27 09:07:14 +02:00
Ben Meadors
30356dcd97 Retroactive trunkinate 2024-09-26 19:46:17 -05:00
Jonathan Bennett
5f6d9c3e27 Add pkc test (#4878)
* Add a second delay() to get the unit tests running on Rak4631

* Add test_PKC_Decrypt

* Remove cruft from test case
2024-09-26 19:33:08 -05:00
TheMalkavien
4794cdb120 Fix (some ?) memory alignment issues on the crypto part - resulting in crashes or strange behavior (#4867)
* Replace multiple potentially non aligned pointer dereference (#4855)
First step to fix some Crypto crashes or strange behaviors

* Makes the two Crypto byte buffers aligned (#4855)
Fix #4855, and probably multiple Crypto problems depending on hardware

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: GUVWAF <78759985+GUVWAF@users.noreply.github.com>
2024-09-26 17:44:11 -05:00
Thomas Göttgens
a32233bb92 fixa de typo too 2024-09-26 12:15:37 +02:00
Thomas Göttgens
fff2e435b5 Merge branch 'master' into t3s3-1121 2024-09-26 12:13:45 +02:00
Thomas Göttgens
8f84a96b69 refactor: typo fix in macro definition 2024-09-26 12:12:08 +02:00
Thomas Göttgens
11c17ec78c oh well 2024-09-26 11:39:35 +02:00
Thomas Göttgens
b4bdf604f5 tryfix 2024-09-26 11:08:49 +02:00
Thomas Göttgens
833d7f65bc fix toolchains between old and new ESP32 2024-09-26 10:18:45 +02:00
Ben Meadors
9bebad2dbe Trunkt 2024-09-25 19:54:14 -05:00
Szetya
14019f2afa Update WaypointModule.cpp (#4870)
In INVERTED display mode, the compass ring was not visible.
2024-09-25 19:09:27 -05:00
Thomas Göttgens
12481b568a fix a lot of nuisances reported by cppcheck (#4872)
* fix a lot of nuisances reported by cppcheck

* fix portduino
2024-09-25 19:09:06 -05:00
Thomas Göttgens
3072b2a444 Merge branch 'master' into esp32-c6 2024-09-26 00:20:00 +02:00
Thomas Göttgens
5c77e29d66 Merge branch 'master' into t3s3-1121 2024-09-26 00:17:41 +02:00
Thomas Göttgens
118809fbfc Account for size of Envelope when allocating buffer. (#4819)
* Account for size of Envelope when allocating buffer.

INFO  | 09:29:20 568 [mqtt] Subscribing to msh/2/e/LongFast/+
INFO  | 09:29:20 568 [mqtt] Subscribing to msh/2/json/LongFast/+
INFO  | 09:29:20 568 [mqtt] Subscribing to msh/2/e/PKI/+
DEBUG | 09:29:20 568 [mqtt] Publishing enqueued MQTT message
ERROR | 09:29:20 568 [mqtt] Panic: can't encode protobuf reason='bytes size exceeded'

assert failed: size_t pb_encode_to_bytes(uint8_t*, size_t, const pb_msgdesc_t*, const void*) mesh-pb-constants.cpp:18 (0)

* save some mem
2024-09-25 17:13:04 -05:00
Ben Meadors
baf9cf5a59 Encapsulate RadioLibInterface receive IRQ logic (#4866)
* Encapsulate RadioLibInterface receive IRQ logic

* More concise

* Trunk
2024-09-25 16:19:18 -05:00
Ben Meadors
51e4b364b0 Trunk things 2024-09-25 16:18:45 -05:00
Thomas Göttgens
581686c7b7 Merge pull request #4780 from augustozanellato/detsensor_broadcast_changes
DetectionSensor: more flexible triggering
2024-09-25 22:48:57 +02:00
Ben Meadors
3a2fa118a2 Merge branch 'master' into detsensor_broadcast_changes 2024-09-25 13:57:49 -05:00
Ben Meadors
ac5edf867c Create SECURITY.md (#4868) 2024-09-25 13:55:04 -05:00
Thomas Göttgens
d4e8452c60 Tbeams have no ADC (#4871) 2024-09-25 13:51:11 -05:00
Ben Meadors
4128d75ad4 IS_ONE_OF macro to make long chains of conditions more concise and easy to follow (#4860)
* Is one of macro

* Moar

* Whoops

* Trunk

* isOneOf function backed macro
2024-09-25 13:50:00 -05:00
Augusto Zanellato
ed4527cfa5 address review comments 2024-09-25 20:02:22 +02:00
Thomas Göttgens
26112ba001 Support T3S3 LR1121 variant 2024-09-25 18:56:17 +02:00
Ben Meadors
9dd769586f Version 2024-09-25 08:40:33 -05:00
Ben Meadors
6e1616375e Trunk update 2024-09-25 07:25:45 -05:00
Ben Meadors
a7c379961a New detection sensor trigger type value 2024-09-25 07:01:15 -05:00
Ben Meadors
02d9d8b76c Merge branch 'master' into detsensor_broadcast_changes 2024-09-25 06:30:09 -05:00
todd-herbert
d1138d51e5 Wrangle module frames with I2C keyboard (#4817)
* Only suppress UI nav if module using keyboard input

* CardKB combo to dismiss text message and waypoint
Currently assigned to Fn + Delete
2024-09-25 06:27:04 -05:00
Ben Meadors
31e952c72e Merge branch 'master' into detsensor_broadcast_changes 2024-09-25 06:26:14 -05:00
github-actions[bot]
9d7938f570 [create-pull-request] automated change (#4865)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-09-25 06:25:56 -05:00
David
9456c42fc0 Refactor AccelerometerThread.h (#4831)
* Initial upload

* Tidy up

* Update ICM20948Sensor.cpp

* Update AccelerometerThread.h

* Initial upload

* Tidy up

* Update ICM20948Sensor.cpp

* Update AccelerometerThread.h

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-25 06:25:31 -05:00
David
40b3dbaa70 Add MAX17048 lipo fuel gauge (#4851)
* Initial commit

* Update MAX17048Sensor.cpp

* Update EnvironmentTelemetry.cpp

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-25 05:34:53 -05:00
Jonathan Bennett
1129c92974 Add a second delay() to get the unit tests running on Rak4631 (#4862) 2024-09-25 05:31:29 -05:00
dylanli
1293c5cdd4 Support for Seeed XIAO S3 Board (#4850)
* feat: add seeed-xiao-s3 board defination and pins defination

* chore:  add SEEED XIAO S3 into mesh pb

* fix: fix trunk fmt check failed

* Trunk fmt variant.h

* Restore automatically generated file

---------

Co-authored-by: Tom Fifield <tom@tomfifield.net>
2024-09-25 18:27:14 +08:00
Thomas Göttgens
bebd2bb9e0 Merge pull request #4863 from meshtastic/create-pull-request/patch
Update protobufs and classes
2024-09-25 10:29:27 +02:00
caveman99
f73aa8aa82 [create-pull-request] automated change 2024-09-25 08:28:33 +00:00
Ben Meadors
c50df710ba Also put this back 2024-09-24 20:12:42 -05:00
Thomas Göttgens
65104d5d8c fix #4844 (#4859) 2024-09-24 16:51:07 -05:00
Augusto Zanellato
881f133021 Merge branch 'master' into detsensor_broadcast_changes 2024-09-24 23:00:35 +02:00
Ben Meadors
10c51d8a05 Put this back 2024-09-24 15:44:16 -05:00
Ben Meadors
453b3a59b2 python3 ref 2024-09-24 15:24:08 -05:00
Ben Meadors
67fd4b64af Actual ref 2024-09-24 15:20:05 -05:00
Ben Meadors
1d0013918b master ref 2024-09-24 15:15:55 -05:00
Ben Meadors
cac640ea97 Meshtestic submodule update 2024-09-24 14:57:20 -05:00
Ben Meadors
e7569838c7 Bin path 2024-09-24 14:32:20 -05:00
Ben Meadors
64b2bf5f93 Checkout should handle this but oh well 2024-09-24 14:18:19 -05:00
Ben Meadors
d6a008500a Who chose that ridiculous name anyway?! 2024-09-24 14:05:12 -05:00
Ben Meadors
a9d636c025 Consolidate commands 2024-09-24 14:02:12 -05:00
Ben Meadors
292027f40f Setup node 2024-09-24 13:57:53 -05:00
Ben Meadors
3c126212d5 PIO script 2024-09-24 13:45:02 -05:00
Ben Meadors
9710ac79d3 Pipargs 2024-09-24 13:37:40 -05:00
Ben Meadors
f2801a660b Update tests.yml 2024-09-24 13:33:51 -05:00
Ben Meadors
4d269501dd No args 2024-09-24 13:30:26 -05:00
Ben Meadors
752192b09a pipx 2024-09-24 13:27:13 -05:00
Ben Meadors
f8f9329529 pip3 2024-09-24 13:16:24 -05:00
github-actions[bot]
c3e53d916d [create-pull-request] automated change (#4858)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-09-24 13:04:52 -05:00
Ben Meadors
c679932248 Setup python 2024-09-24 12:58:41 -05:00
Ben Meadors
5488c8f579 Got the runner labels backwards 2024-09-24 12:54:04 -05:00
Ben Meadors
6c488fe816 Ony run on test runner label 2024-09-24 12:43:39 -05:00
Ben Meadors
771cb52616 Remove amd64 2024-09-24 10:52:46 -05:00
Ben Meadors
10869ea10a Don't wait for after-checks 2024-09-24 09:10:29 -05:00
Ben Meadors
e4d0e38f37 Remove native and add v4 back 2024-09-24 08:25:25 -05:00
Ben Meadors
d7badcc9cb Don't run checks on workflow_dispatch 2024-09-24 07:17:38 -05:00
Ben Meadors
4fbf666cd9 Try v3 2024-09-24 07:12:43 -05:00
Tom Fifield
adb094ebc9 Remove old comments from main (#4849)
These comments were circa 4 years old. Remove them.
2024-09-24 06:08:32 -05:00
Tom Fifield
b709d47832 Fix Ublox M10 Setup (#4842)
There is no EXTINT pin available on the Tdeck, which uses
the Ublox M10 GPS. Therefore our previous hack to use that pin
makes the GPS not work. That workaround was implemented to
fix sleep issues which have now since been fixed with the
state machine.

This patch restores the state prior to the hack, which is
known-working.

Additionaly, it was discovered that M10s hate it when you
try and save to non-extistent eeprom/SPI flash.

This patch creates a new SAVE command for the M10 that fixes
this issue.

Many thanks to @MisterC925 whose report and testing was
essential for this fix.

fixes https://github.com/meshtastic/firmware/issues/4625

Co-authored-by: Ken McGuire <kenm@paonia.com>
2024-09-24 05:50:03 -05:00
Augusto Zanellato
01d42d4728 Merge branch 'master' into detsensor_broadcast_changes 2024-09-24 11:53:41 +02:00
Augusto Zanellato
ce480ae626 fix comment style 2024-09-24 11:16:04 +02:00
Augusto Zanellato
139686d639 bump protobufs 2024-09-24 11:11:16 +02:00
Jason Murray
4fde1ca2a8 chomp trailing newline (#4848) 2024-09-24 16:27:46 +08:00
Jason Murray
c72612d826 sed doesn't like newlines (#4847)
* sed doesn't like newlines

* fold remove-debug-flags block

* PATH is a system env var

* Runners don't like rm -f ${workspace path}
2024-09-24 15:41:40 +08:00
Tom Fifield
682133501a Syntax fix for github action (#4846)
https://docs.github.com/en/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions
2024-09-24 14:49:01 +08:00
Jason Murray
b4c09ace23 Consolidate variant build steps (#4820)
* poc: consolidate variant build steps

* use build-variant action

* only checkout once and clean up after run

* checkout before local action
2024-09-24 13:47:31 +08:00
Jonathan Bennett
c39d270f40 Build message in printBytes, to not spam BLE log (#4843) 2024-09-24 12:41:28 +08:00
Tom Fifield
428a567078 Wire 1 is PIN_WIRE1_SDA (#4840)
Based on #4745, PIN_WIRE1_SDA is the 'second' wire interface.

This pach amends the check to determine whether a device has two
wire interfaces should use PIN_WIRE1_SDA, rather than PIN_WIRE_SDA.
2024-09-23 19:16:44 -05:00
Ben Meadors
0ad1f776ae Manually regen protos for now 2024-09-23 18:53:01 -05:00
Ben Meadors
e78c706999 Fix RAK4631 accelerometer (#4837) 2024-09-23 18:40:54 -05:00
Ben Meadors
c442cd7267 Remove some straggler now 2024-09-23 15:53:42 -05:00
Ben Meadors
9cbabb0468 Teardown bluetooth phoneAPI better and fix client notification issue (#4834)
* Teardown bluetooth phoneAPI better and fix client notification issue

* Fix client notification draining
2024-09-23 15:51:05 -05:00
Jonathan Bennett
9a7a4d3814 Check for null before printing debug (#4835) 2024-09-23 13:56:26 -05:00
Jonathan Bennett
fa1cc59841 Rename message length headers and set payload max to 255 (#4827)
* Rename message length headers and set payload max to 255

* Add MESHTASTIC_PKC_OVERHEAD

* compare to MESHTASTIC_HEADER_LENGTH

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2024-09-23 09:20:32 -05:00
Augusto Zanellato
d4dc4dec76 Merge branch 'master' into detsensor_broadcast_changes 2024-09-23 16:20:20 +02:00
Augusto Zanellato
be01c18c74 DetectionSensor: more flexible triggering 2024-09-23 16:15:44 +02:00
Ben Meadors
e8829b8f52 Refactor and consolidate time window logic (#4826)
* Refactor and consolidate windowing logic

* Trunk

* Fixes

* More

* Fix braces and remove unused now variables.

There was a brace in src/mesh/RadioLibInterface.cpp that was breaking
compile on some architectures.

Additionally, there were some brace errors in
src/modules/Telemetry/AirQualityTelemetry.cpp
src/modules/Telemetry/EnvironmentTelemetry.cpp
src/mesh/wifi/WiFiAPClient.cpp

Move throttle include in WifiAPClient.cpp to top.

Add Default.h to sleep.cpp

rest of files just remove unused now variables.

* Remove a couple more meows

---------

Co-authored-by: Tom Fifield <tom@tomfifield.net>
2024-09-23 08:58:14 -05:00
Thomas Göttgens
1afd61698b Merge pull request #4745 from todd-herbert/t114-i2c
I2C for Heltec Mesh Node T114
2024-09-23 15:45:35 +02:00
Jason Murray
3ff9398b92 Revert "Update classes on protobufs update" (#4824)
* Revert "Update classes on protobufs update"

* remove quotes to fix trunk.

---------

Co-authored-by: Tom Fifield <tom@tomfifield.net>
2024-09-23 20:34:19 +08:00
Todd Herbert
76900555e8 Swap SDA and SCL
SDA=P0.16, SCL=P0.13
2024-09-24 00:25:43 +12:00
Todd Herbert
1487ca2a30 Tidier macros 2024-09-24 00:25:43 +12:00
Todd Herbert
f960164c0e Add I2C bus to Heltec T114 header pins
SDA: P0.13
SCL: P0.16

Uses bus 1, leaving bus 0 routed to the unpopulated footprint for the RTC (general future-proofing)
2024-09-24 00:25:43 +12:00
Todd Herbert
11598beb16 Implement optional second I2C bus for NRF52840
Enabled at compile-time if WIRE_INFERFACES_COUNT defined as 2
2024-09-24 00:25:43 +12:00
Tom Fifield
1f8aa1efc7 Minor fix (#4666)
* Minor fixes

It turns out setting a map value with the index notation causes
an lookup that can be avoided with emplace. Apply this to one line in
the StoreForward module.

Fix also Cppcheck-determined highly minor performance increase by
passing gpiochipname as a const reference :)

The amount of cycles used on this laptop while learning about these
callouts from cppcheck is unlikely to ever be more than the cycles
saved by the fixes ;)

* Update PortduinoGlue.cpp
2024-09-23 18:22:06 +08:00
Jonathan Bennett
18aac0ba25 Consider the LoRa header when checking packet length 2024-09-22 16:09:46 -05:00
Tom Fifield
2e24d244be Make Ublox code more readable (#4727)
* Simplify Ublox code

Ublox comes in a myriad of versions and settings. Presently our
configuration code does a lot of branching based on versions being
or not being present.

This patch adds version detection earlier in the piece and branches
on the set gnssModel instead to create separate setup methods for Ublox 6,
Ublox 7/8/9, and Ublox10.

Additionally, adds a macro to make the code much shorter and more
readable.

* Make trunk happy

* Make trunk happy

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-22 10:00:32 -05:00
Tom Fifield
7db98ca1da Revert "Consolidate variant build steps (#4806)" (#4816)
This reverts commit 9f8d86cb25.
2024-09-22 19:39:35 +08:00
Jason Murray
9f8d86cb25 Consolidate variant build steps (#4806)
* poc: consolidate variant build steps

* use build-variant action

* only checkout once and clean up after run
2024-09-22 19:22:00 +08:00
Austin
2ff0af55b1 [Board] DIY "t-energy-s3_e22" (#4782)
* New variant "t-energy-s3_e22"

- Lilygo T-Energy-S3
- NanoVHF "Mesh-v1.06-TTGO-T18" board
- Ebyte E22 Series

* add board_level = extra

* Update variant.h

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: Tom Fifield <tom@tomfifield.net>
2024-09-22 14:47:49 +08:00
Ben Meadors
51af747508 CI fixes 2024-09-21 20:53:23 -05:00
Ben Meadors
893bbe09d1 Hopefully extract and commit to meshtastic.github.io 2024-09-21 16:34:26 -05:00
Jonathan Bennett
d21087f639 Update platform-native to pick up portduino crash fix (#4807) 2024-09-21 16:17:30 -05:00
Thomas Göttgens
01203eb854 Merge pull request #4805 from scruplelesswizard/update-classes-on-protobuf-update
Update classes on protobufs update
2024-09-21 21:46:32 +02:00
Jason Murray
2072ebd196 meshtastic/ is a test suite; protobufs/ contains protobufs; 2024-09-21 09:58:28 -07:00
Jason Murray
202699239f feat: trigger class update when protobufs are changed 2024-09-21 07:51:09 -07:00
Thomas Göttgens
906b0233d2 Merge pull request #4801 from meshtastic/heltec-wireless-bridge
heltec-wireless-bridge
2024-09-21 16:15:28 +02:00
Thomas Göttgens
d584031d10 Merge pull request #4804 from meshtastic/create-pull-request/patch
Update protobufs and classes
2024-09-21 15:16:52 +02:00
thebentern
f324ab7de7 [create-pull-request] automated change 2024-09-21 15:16:31 +02:00
todd-herbert
54f56438da Re-order doDeepSleep (#4802)
Make sure PMU sleep takes place before I2C ends
2024-09-21 07:59:17 -05:00
Thomas Göttgens
e6c7c80b3f Raspberry Pico2 - needs protos 2024-09-21 14:50:19 +02:00
dependabot[bot]
c053c7d9ae Bump pnpm/action-setup from 2 to 4 in /.github/workflows (#4798)
Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 2 to 4.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v2...v4)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-21 06:13:09 -05:00
github-actions[bot]
953beb56b1 [create-pull-request] automated change (#4789)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-09-21 06:12:05 -05:00
dependabot[bot]
acd044fdea Bump meshtestic from 31ee3d9 to 37245b3 (#4799)
Bumps [meshtestic](https://github.com/meshtastic/meshTestic) from `31ee3d9` to `37245b3`.
- [Commits](31ee3d90c8...37245b3d61)

---
updated-dependencies:
- dependency-name: meshtestic
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-21 06:11:32 -05:00
Tom Fifield
de706523f5 Actions: Semgrep Images have moved from returntocorp to semgrep (#4774)
https://hub.docker.com/r/returntocorp/semgrep notes: "We've moved!
 Official Docker images for Semgrep now available at semgrep/semgrep."

Patch updates our CI workflow for these images.

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-21 06:10:59 -05:00
Thomas Göttgens
52cef05c70 heltec-wireless-bridge
requires Proto PR first
2024-09-21 12:42:51 +02:00
dependabot[bot]
6490cadd35 Bump docker/build-push-action from 5 to 6 in /.github/workflows (#4800) 2024-09-21 09:30:36 +00:00
Thomas Göttgens
8e5928276b update pin definitions
update toolchain
enable telemetry
fix compilation
2024-09-21 11:27:14 +02:00
Thomas Göttgens
5dcaceccdd Merge branch 'esp32-c6' of github.com:meshtastic/firmware into esp32-c6 2024-09-21 11:24:58 +02:00
Thomas Göttgens
f1cf2bf413 First stab at ESP32-C6 support for TLora-C6 2024-09-21 11:24:52 +02:00
dependabot[bot]
3882841283 Bump peter-evans/create-pull-request from 6 to 7 in /.github/workflows (#4797) 2024-09-21 08:17:31 +00:00
Tom Fifield
74e6470439 fix dependabot syntax (#4795)
* fix dependabot syntax

* Update dependabot.yml

* Update dependabot.yml
2024-09-21 14:20:30 +08:00
Tom Fifield
dca711ac24 Merge pull request #4790 from scruplelesswizard/master
Enable Dependabot
2024-09-21 12:22:11 +08:00
Jason Murray
7368cb99dc chore: trunk fmt 2024-09-20 19:40:36 -07:00
Jason Murray
ec848bab52 Enable Dependabot 2024-09-21 09:40:56 +08:00
Jason Murray
ed13105aec set title for version bump PR (#4791) 2024-09-20 20:30:49 -05:00
Jason Murray
c2272ce5a1 set title for protobufs bump PR (#4792) 2024-09-20 20:30:32 -05:00
Ben Meadors
0664c09f9d Download debian files after firmware zip 2024-09-20 14:55:53 -05:00
todd-herbert
ba31a7c753 Honor flip & color for Heltec T114 and T190 (#4786)
* Honor TFT_MESH color if defined for Heltec T114 or T190

* Temporary: point lib_deps at fork of Heltec's ST7789 library
For demo only, until ST7789 is merged

* Update lib_deps; tidy preprocessor logic
2024-09-20 13:27:41 -05:00
Thomas Göttgens
1bca8de042 Merge branch 'esp32-c6' of github.com:meshtastic/firmware into esp32-c6 2024-09-20 19:37:51 +02:00
Thomas Göttgens
6ffdc9875b First stab at ESP32-C6 support for TLora-C6 2024-09-20 19:37:47 +02:00
Thomas Göttgens
b84cf55659 Merge branch 'esp32-c6' of github.com:meshtastic/firmware into esp32-c6 2024-09-20 19:37:24 +02:00
Ben Meadors
85d722232e Additional decoded packet ignores 2024-09-20 07:35:26 -05:00
Ben Meadors
921d92c649 Drop received packets from self 2024-09-20 06:55:16 -05:00
Jonathan Bennett
0f3450ad44 Mark package workflows for gh hosted runners 2024-09-19 18:21:30 -05:00
Jonathan Bennett
114df8cb1b Pin sensorlib version 2024-09-19 13:29:17 -05:00
Jonathan Bennett
d3a293a0d8 Flag semgrep to not run on self-hosted
The semgrep action runs inside a docker container, and docker in podman just doesn't work.
2024-09-19 12:10:39 -05:00
Ben Meadors
91b4199f9d Revert "DetectionSensor: broadcast all state changes" (#4776) 2024-09-19 10:46:18 -05:00
Tom Fifield
6473cf0b69 Update RadioLib to 7.0.0 (#4771)
We were not too many commits behind, and the changes since then
were either for LoraWAN or useful minor bug fixes for SX1280.
2024-09-19 06:48:22 -05:00
Tom Fifield
84e197574b Merge pull request #4773 from markbirss/master
Update HW_VENDOR
2024-09-19 16:28:40 +08:00
Mark Trevor Birss
5c4c0965af Update nordic_pca10059.json 2024-09-19 15:41:59 +08:00
Mark Trevor Birss
7289b295e8 Update me25ls01-4y10td.json 2024-09-19 15:41:59 +08:00
Mark Trevor Birss
7c32ab3023 Update ms24sf1.json 2024-09-19 15:41:59 +08:00
Tom Fifield
2bc036f9eb Merge pull request #4772 from dahanc/master
Another missed define for the T114
2024-09-19 15:28:26 +08:00
David Huang
cc89e85e71 Another missed define for the T114 2024-09-19 00:53:33 -05:00
Tom Fifield
da45cb8557 Merge pull request #4767 from augustozanellato/detsensor_broadcast_changes
DetectionSensor: broadcast all state changes
2024-09-19 13:42:56 +08:00
Augusto Zanellato
2ebfcea94e DetectionSensor: broadcast all state changes
Closes #4753
2024-09-18 19:43:23 +02:00
github-actions[bot]
deada41cee [create-pull-request] automated change (#4765)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-09-18 10:49:12 -05:00
Ben Meadors
777bcf691a Initial PhoneAPI rate-limiting of messages on certain ports (#4756) 2024-09-18 10:13:07 -05:00
Tom Fifield
35e1c401e2 PMSA0031 sensors require ~3secs before coming up on I2C (#4743)
* PMSA0031 sensors require ~3secs before coming up on I2C

As reported by @MALAONE1 and debugged by @shodan8192 , PMSA0031s
on a RAK4631 take 3 seconds before they can become detectable on I2c.

Add a delay(4000) before I2C scan if the air quality sensor pin
is defined.

Fixes https://github.com/meshtastic/firmware/issues/3690

* Remove 4 second wait and rescan during air quality init for the sensor

* works without but this triggers my OCD

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-18 10:12:49 -05:00
Tom Fifield
19c57e8ec6 Fix Chatter 2 blank screen on boot (#4759)
As reported by @eureekasigns and @GPSFan, Chatter 2 had begun
to show a blank screen on boot after recent TFT display changes.

Setting TFT_BACKLIGHT_ON LOW resolves the issue.

Fixes https://github.com/meshtastic/firmware/issues/4751
2024-09-18 09:05:32 -05:00
Jonathan Bennett
c6196b2260 Update build_esp32.yml -- less CI fun 2024-09-18 01:11:08 -05:00
Jonathan Bennett
3eebdcefa4 More CI fun 2024-09-18 00:28:54 -05:00
Jonathan Bennett
4289cb089b Update package_raspbian.yml to build on self-hosted (#4761)
* Update package_raspbian.yml to build on self-hosted

* Update package_raspbian_armv7l.yml to use self hosted
2024-09-18 00:17:48 -05:00
Jonathan Bennett
2d52803dbd Add new admin error types (#4750)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-17 21:09:24 -05:00
Jonathan Bennett
c78302a2ee Add hasPKC to deviceMetadata (#4755) 2024-09-17 19:34:05 -05:00
github-actions[bot]
923458bc18 [create-pull-request] automated change (#4754)
Co-authored-by: jp-bennett <5630967+jp-bennett@users.noreply.github.com>
2024-09-17 17:55:16 -05:00
Ben Meadors
50fb4ab22a Implement optional hops_away on NodeInfo/Lite (#4747)
* Implement optional hops_away on NodeInfo/Lite

* Trunk
2024-09-17 12:08:04 -05:00
Thomas Göttgens
f5016763fd change evaluation order to silence warning about "found" (#4749) 2024-09-17 10:33:21 -05:00
Ben Meadors
2a6921292e Implement CoT detail support in TAKPacket (#4748)
* Implement CoT detail support in TAKPacket

* dest, src

* More coffee is needed

* SAVE
2024-09-17 10:05:55 -05:00
github-actions[bot]
a47570d65a [create-pull-request] automated change (#4746)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-09-17 06:52:42 -05:00
Andre K
db4dc88d6f feat: enable remote admin to set/clear fixed positions (#4713)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-17 06:50:49 -05:00
Tom Fifield
be306cc384 Increase GPS FIFO Buffer Size for RP2040 (#4741)
As discovered and tested by @Mictronics, default Serial FIFO size
on the Pico is 32bytes, which is not enough for GPS messages.

This patch increases the Serial GPS FIFO buffer size to 256
for the RP2040 Architecture

fixes https://github.com/meshtastic/firmware/issues/3989
2024-09-17 06:48:56 -05:00
Jonathan Bennett
a967dd52f3 More useful PKC logging (#4742) 2024-09-17 06:31:39 -05:00
Ben Meadors
11378325e0 Separate GPS and NTP RTCQuality logic and allow GPS time to always set us (#4721) 2024-09-17 06:29:18 -05:00
Thomas Göttgens
4b5bcf52d2 Merge pull request #4691 from S5NC/rak11200-pin-name-correction
Rak11200 pin name correction
2024-09-17 11:42:40 +02:00
Thomas Göttgens
5ba418b2cd Merge pull request #4744 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2024-09-17 09:27:42 +02:00
Thomas Göttgens
bc753e6903 trunk fmt 2024-09-17 15:24:11 +08:00
S5NC
34a543ec74 Update main.cpp 2024-09-17 15:24:11 +08:00
S5NC
06cd9abd81 Update SX126xInterface.cpp 2024-09-17 15:24:11 +08:00
S5NC
af30485611 Update main.cpp 2024-09-17 15:24:11 +08:00
S5NC
cd6bd1e9a3 Update main.cpp 2024-09-17 15:24:11 +08:00
S5NC
b025eeb13c Update variant.h 2024-09-17 15:24:11 +08:00
Thomas Göttgens
21eb54e58a Merge pull request #4740 from fifieldt/QMC5883L
Fix I2C address for QMC5883L.
2024-09-17 09:09:43 +02:00
Tom Fifield
6f1db6fc63 Fix I2C address for QMC5883L.
QMC5883L and HMC5883L are 3-axis compasses which are often confused.
As reported by @Africmod, we had the wrong I2C address for the QMC5883L.
This patch fixes the address and adds its HMC5883L so we keep info
about both.

Fixes https://github.com/meshtastic/firmware/issues/4144
2024-09-17 13:48:10 +08:00
Tom Fifield
a5118787b3 Merge pull request #4689 from Szetya/master
Improved compass arrow
2024-09-17 13:02:52 +08:00
jp-bennett
39c90dd581 [create-pull-request] automated change 2024-09-17 02:53:44 +00:00
Todd Herbert
33e6f7f6e0 Hollow triangle for E-Ink; trunk formatting 2024-09-17 08:27:00 +08:00
Szetya
97fd189f43 Compass update
https://github.com/meshtastic/firmware/issues/4494
New compass arrow and replacement of the north marker with a small circle.
2024-09-17 08:27:00 +08:00
jhps
1e665d5181 Update T114 LED definitions to include only one simple controllable LED and two NEOPIXELS. (#4710) 2024-09-16 19:11:55 -05:00
Thomas Göttgens
b3343303a9 write firmware version and hardware platform to Flash memory 2024-09-16 21:36:54 +02:00
github-actions[bot]
f37276d5fc [create-pull-request] automated change (#4736)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-09-16 10:32:21 -05:00
Tom Fifield
905194c604 Remove lora_isp4520 (#4735)
Per Ben: "We haven't supported any NRF5832 based board in quite some time.
It's relatively resource constrained compared to the NRF52840"
2024-09-16 09:06:13 -05:00
Thomas Göttgens
ea6f6c3668 First stab at ESP32-C6 support for TLora-C6 2024-09-16 14:25:17 +02:00
Thomas Göttgens
51b22630b4 Merge pull request #4728 from fifieldt/11111111111111111
Fix Heltec T114 vendor definition
2024-09-16 12:20:18 +02:00
Mark Trevor Birss
5d831ef461 Merge pull request #4729 from markbirss/master
[BUG-FIX] ME25LS01-4Y10TD_e-ink e-paper init fix
2024-09-16 11:14:16 +02:00
Mark Trevor Birss
4e8672cce4 Update variant.h 2024-09-16 10:40:52 +02:00
Tom Fifield
41a769aa06 Fix Heltec T114 vendor definition
@dahanc pointed out there was an extra one in there.
2024-09-16 13:55:27 +08:00
Ben Meadors
8d57b6164a Add Heltec T1114 hardware model to build (#4719) 2024-09-15 20:37:19 -05:00
Ben Meadors
dc3eba9100 Expand to MqttClientProxyMessage_size (#4726) 2024-09-15 18:57:02 -05:00
Jonathan Bennett
ff8baa1c85 Don't use PKC on a non-primary channel unless specifically requested (#4715)
* Don't use PKC on a non-primary channel unless specifically requested

* Don't change from channel 0 if we can send a PKC packet.
2024-09-15 09:26:43 -05:00
Jonathan Bennett
3a10a27851 Actually restrict remote hardware to gpio channel (#4717) 2024-09-15 06:27:59 -05:00
GUVWAF
8893529653 Make local stats number of Rx packets sum of good and bad (#4709) 2024-09-14 17:53:27 -05:00
Jonathan Bennett
1ab5bf4355 Use the time.age() value to correct stale GPS times (#4705)
* Use the time.age() value to correct stale GPS times

* Trunk

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-14 07:44:40 -05:00
Ben Meadors
ae791ca7e1 Add buildstamp epoch to initial debug output 2024-09-13 19:43:50 -05:00
Ben Meadors
35cfe4318a Stop past timestamps from setting our system time RTC (#4704)
* Ignore attempts to set times in the past (before our build epoch)

* TRONK
2024-09-13 19:42:31 -05:00
rcarteraz
b59bd6fee9 Update feature.yml (#4700) 2024-09-13 16:11:54 -05:00
rcarteraz
8b911f14cf Update Bug Report.yml (#4702) 2024-09-13 16:11:39 -05:00
Ben Meadors
d36c69396b Exclude meshtasticd binaries from firmware.zip (#4698)
* Exclude meshtasticd binaries from firmware.zip

* Incorrect
2024-09-13 10:42:40 -05:00
Thomas Göttgens
9527874815 First stab at ESP32-C6 support for TLora-C6 2024-09-12 22:42:10 +02:00
Vertex
3d72fbb19e Define SX126X_ANT_SW for the RAK11200 to allow it to function correctly on the RAK19007 base (#4690) 2024-09-12 12:20:38 -05:00
Manuel
625254cf90 Support Seeed SenseCAP Indicator (#4279)
* preliminary target environment

* add debug tool

* add screen definitions

* screen definitions

* remove rtc, debug build

* correct rotation

* Add real hwmodel

* fix width

* use IO expander ports

* link to modified arduino-esp32

* added config_detail

* rotate screen

* remove touch INT

* add delay to display log

* color log and radiolib log

* LoRa init

* make trunk happy

* add lovyanGFX patch lib for io expander

* fix lib

* fix display&touch function

* touch driver I2C scan

* remove delay

* build for release

* minor code cleanup

* allow trunk to be happy

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2024-09-12 06:44:30 -05:00
panaceya
910b6b7512 OLED_ can be configured via userPrefs.h (#4624) 2024-09-11 19:31:30 -05:00
Tom Fifield
371c3e05bf Beautify GPS_DEBUG getACK logging code (#4672)
This getACK is used to look for ASCII responses, so print ASCII
when GPS_DEBUG is enabled.

This markedly assisted with recent AG3335 debugging. It works great
with other chips too (tested eg ATGM336H). Even UBLOX prints
understandable "GPTXT,01,01,01,PDTI inv format*35." responses.

Credit to bluebrolly. on discord.
2024-09-11 19:30:29 -05:00
Michael Gjelsø
f37df4d6bf Radiomaster Bandit Accelerometer support (#4667)
* Added STK8xxxx Accelerometer chip

Added detection of STK8BA53 to I2C scanner.
Change the way and order MCP9808, lLISH3DH and STK8BA53 is detected since they all shares the same I2C address.

* Accelerometer support Radiomaster Bandit.

Enables tap to wake screen if enabled in config,

* Trunk

Trunk
2024-09-11 18:53:17 -05:00
github-actions[bot]
ba9a3cd719 [create-pull-request] automated change (#4685)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-09-11 18:51:52 -05:00
Ben Meadors
9ac0e26d42 Add option to preserve private key for factory reset (config) (#4679)
* Add option to preserve private key for factory reset (config)

* Typo fix

* Copy the key in the right direction, and set the size.

* Don't set the key size back to 0 right after setting it to 32.

* Set the key size before using it to do a memcpy.

* Use the right key_size for backing up private_key

* Don't factoryReset() for a missing nodeDB

* Disable Bluetooth in AdminModule when resetting device settings or nodeDB to avoid race

* Add checks for valid objects before deinit bluetooth

* Add disableBluetooth to handleSetConfig, handleSetModuleConfig, and commit settings

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2024-09-11 08:42:26 -05:00
Ben Meadors
1ba4f6e222 Revert "Temp: Grab pre-release tag"
This reverts commit e8e9826adc.
2024-09-10 20:07:06 -05:00
Ben Meadors
e8e9826adc Temp: Grab pre-release tag 2024-09-10 19:27:59 -05:00
zerolint
6724f1f7ea Print Unix epoch on time_t 64bit platforms (#4673)
Fixes (#4600) by using unsigned 32bit for epoch.

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-09-10 15:51:28 -05:00
Ben Meadors
013021941e Remove scaling of smart position broadcast minimum interval specifically (#4677)
* Remove scaling of smart position broacast minimum interval specifically

* Trunk
2024-09-10 15:30:40 -05:00
Jonathan Bennett
4e850296b6 Fix repeatedly getting new NodeNum and add more debug (#4674)
* All the debug

* Change `memccpy()` to `memcpy()`

* Brint all the bytes of the MAC Address from the NodeDB

* Check for blank MAC Address in ourown NodeDB entry

* One more `memccpy()`

* Clean-up debug log

---------

Co-authored-by: GUVWAF <thijs@havinga.eu>
2024-09-10 13:24:57 -05:00
GUVWAF
f1602ee3f6 Merge pull request #4669 from GUVWAF/trFix 2024-09-09 23:13:39 +02:00
GUVWAF
5537f98dd6 Merge branch 'master' into trFix 2024-09-09 21:29:37 +02:00
GUVWAF
4ed12bf21d Try fix repeatedly getting a new NodeNum (#4670) 2024-09-09 14:22:32 -05:00
Ben Meadors
106dab23db Revert "Changes by create-pull-request action" (#4671) 2024-09-09 14:20:14 -05:00
GUVWAF
2f9dcee954 Fix size calculation of route/SNR array 2024-09-09 19:13:00 +02:00
Thomas Göttgens
68d6ff8c24 Merge pull request #4650 from fifieldt/AG3352
Add support for AG3352 and fix AG3335 support
2024-09-09 16:40:44 +02:00
Tom Fifield
dc8cc122a6 Add explicit to JSONValue constructors (#4665) 2024-09-09 09:20:21 -05:00
Tom Fifield
e9d55de3cb Fix out-of-bound array access in T1000X Sensor (#4663)
if u8i == 135, then u8i++ runs, the loop exits since u8i == 136,
then value for u8i is 136 after the for loop.

then in the next line, ntc_res2[u8i] will read past the end
 of the array
2024-09-09 07:54:11 -05:00
David
dacb452d47 Bugfix (#4660) 2024-09-09 07:16:58 -05:00
Thomas Göttgens
b2e2f1dba3 Merge branch 'master' into AG3352 2024-09-09 11:10:36 +02:00
Tom Fifield
6217e97c41 Add support for AG3352 and fix AG3335 support
AG33352 is a Mediatek/Airoha GPS/GLONASS/Galileo/BeiDou receiver.
Patch adds relevant detection and setup code.

Thanks to Bluebrolly and kongduino for providing the relevant
information and testing.

This patch also fixes support for the A3335, which is a related chip.
The setup and detection code now works as tested on a real life
T-1000E!

Thanks to @gpsfan for the guidance.
2024-09-09 09:06:05 +08:00
251 changed files with 4675 additions and 1947 deletions

View File

@@ -13,16 +13,13 @@
},
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools",
"platformio.platformio-ide",
]
"extensions": ["ms-vscode.cpptools", "platformio.platformio-ide"]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [ 4403 ],
"forwardPorts": [4403],
// Run commands to prepare the container for use
"postCreateCommand": ".devcontainer/setup.sh",
"postCreateCommand": ".devcontainer/setup.sh"
}

View File

@@ -1,3 +1,3 @@
#!/usr/bin/env sh
git submodule update --init
git submodule update --init

View File

@@ -49,10 +49,24 @@ body:
- Heltec V3
- Heltec Wireless Paper
- Heltec Wireless Tracker
- Heltec Mesh Node T114
- Heltec Vision Master E213
- Heltec Vision Master E290
- Heltec Vision Master T190
- Nano G1
- Nano G1 Explorer
- Nano G2 Ultra
- Raspberry Pi Pico (W)
- Relay v1
- Relay v2
- Seeed Wio Tracker 1110
- Seeed Card Tracker T1000-E
- Station G1
- Station G2
- unPhone
- CanaryOne
- Chatter
- Linux Native
- DIY
- Other
validations:

View File

@@ -18,6 +18,7 @@ body:
- ESP32
- RP2040
- Linux Native
- Cross-Platform
- other
validations:
required: true

View File

@@ -0,0 +1,90 @@
name: Setup Build Variant Composite Action
description: Variant build actions for Meshtastic Platform IO steps
inputs:
board:
description: The board to build for
required: true
github_token:
description: GitHub token
required: true
build-script-path:
description: Path to the build script
required: true
remove-debug-flags:
description: A space separated list of files to remove debug flags from
required: false
default: ""
ota-firmware-source:
description: The OTA firmware file to pull
required: false
default: ""
ota-firmware-target:
description: The target path to store the OTA firmware file
required: false
default: ""
artifact-paths:
description: A newline separated list of paths to store as artifacts
required: false
default: ""
include-web-ui:
description: Include the web UI in the build
required: false
default: "false"
runs:
using: composite
steps:
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
if: inputs.include-web-ui == 'true'
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ inputs.github_token }}
- name: Unpack web ui
if: inputs.include-web-ui == 'true'
shell: bash
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
shell: bash
if: inputs.remove-debug-flags != ''
run: |
for INI_FILE in ${{ inputs.remove-debug-flags }}; do
sed -i '/DDEBUG_HEAP/d' ${INI_FILE}
done
- name: Build ${{ inputs.board }}
shell: bash
run: ${{ inputs.build-script-path }} ${{ inputs.board }}
- name: Pull OTA Firmware
if: inputs.ota-firmware-source != '' && inputs.ota-firmware-target != ''
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: ${{ inputs.ota-firmware-source }}
target: ${{ inputs.ota-firmware-target }}
token: ${{ inputs.github_token }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
${{ inputs.artifact-paths }}

26
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
version: 2
updates:
- package-ecosystem: docker
directory: devcontainer
schedule:
interval: daily
time: "05:00" # trunk-ignore(yamllint/quoted-strings): required by dependabot syntax check
timezone: US/Pacific
- package-ecosystem: docker
directory: /
schedule:
interval: daily
time: "05:00" # trunk-ignore(yamllint/quoted-strings): required by dependabot syntax check
timezone: US/Pacific
- package-ecosystem: gitsubmodule
directory: /
schedule:
interval: daily
time: "05:00" # trunk-ignore(yamllint/quoted-strings): required by dependabot syntax check
timezone: US/Pacific
- package-ecosystem: github-actions
directory: /.github/workflows
schedule:
interval: daily
time: "05:00" # trunk-ignore(yamllint/quoted-strings): required by dependabot syntax check
timezone: US/Pacific

View File

@@ -12,52 +12,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
id: build
uses: ./.github/actions/build-variant
with:
repo: meshtastic/firmware-ota
file: firmware.bin
target: release/bleota.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
remove-debug-flags: >-
./arch/esp32/esp32.ini
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware.bin
ota-firmware-target: release/bleota.bin
artifact-paths: |
release/*.bin
release/*.elf
include-web-ui: true

View File

@@ -14,50 +14,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
- name: Build ESP32-C3
id: build
uses: ./.github/actions/build-variant
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware-c3.bin
target: release/bleota-c3.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
remove-debug-flags: >-
./arch/esp32/esp32.ini
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware-c3.bin
ota-firmware-target: release/bleota-c3.bin
artifact-paths: |
release/*.bin
release/*.elf

35
.github/workflows/build_esp32_c6.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Build ESP32-C6
on:
workflow_call:
inputs:
board:
required: true
type: string
permissions: read-all
jobs:
build-esp32-c6:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build ESP32-C6
id: build
uses: ./.github/actions/build-variant
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
remove-debug-flags: >-
./arch/esp32/esp32.ini
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
./arch/esp32/esp32c6.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware-c3.bin
ota-firmware-target: release/bleota-c3.bin
artifact-paths: |
release/*.bin
release/*.elf

View File

@@ -12,50 +12,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
- name: Build ESP32-S3
id: build
uses: ./.github/actions/build-variant
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware-s3.bin
target: release/bleota-s3.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
remove-debug-flags: >-
./arch/esp32/esp32.ini
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware-s3.bin
ota-firmware-target: release/bleota-s3.bin
artifact-paths: |
release/*.bin
release/*.elf
include-web-ui: true

View File

@@ -67,7 +67,7 @@ jobs:
- name: Docker build and push tagged versions
if: ${{ github.event_name == 'workflow_dispatch' }}
continue-on-error: true # FIXME: Failing docker login auth
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
@@ -77,7 +77,7 @@ jobs:
- name: Docker build and push
if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
continue-on-error: true # FIXME: Failing docker login auth
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile

View File

@@ -12,23 +12,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build NRF52
run: bin/build-nrf52.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
id: build
uses: ./.github/actions/build-variant
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
build-script-path: bin/build-nrf52.sh
artifact-paths: |
release/*.hex
release/*.uf2
release/*.elf

View File

@@ -12,22 +12,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build Raspberry Pi 2040
run: ./bin/build-rpi2040.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
id: build
uses: ./.github/actions/build-variant
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
build-script-path: bin/build-rpi2040.sh
artifact-paths: |
release/*.uf2
release/*.elf

View File

@@ -12,22 +12,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build STM32
run: bin/build-stm32.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
- name: Build STM32WL
id: build
uses: ./.github/actions/build-variant
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
build-script-path: bin/build-stm32.sh
artifact-paths: |
release/*.hex
release/*.bin

View File

@@ -1,4 +1,7 @@
name: CI
concurrency:
group: ci-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
#concurrency:
# group: ${{ github.ref }}
# cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
@@ -24,7 +27,7 @@ jobs:
strategy:
fail-fast: false
matrix:
arch: [esp32, esp32s3, esp32c3, nrf52840, rp2040, stm32, check]
arch: [esp32, esp32s3, esp32c3, esp32c6, nrf52840, rp2040, stm32, check]
runs-on: ubuntu-latest
steps:
- id: checkout
@@ -32,13 +35,18 @@ jobs:
name: Checkout base
- id: jsonStep
run: |
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
echo "$TARGETS"
if [[ "${{ github.head_ref }}" == "" ]]; then
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
else
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} quick)
fi
echo "Name: ${{ github.ref_name }} Base: ${{ github.base_ref }} Head: ${{ github.head_ref }} Ref: ${{ github.ref }} Targets: $TARGETS"
echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT
outputs:
esp32: ${{ steps.jsonStep.outputs.esp32 }}
esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }}
esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }}
esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }}
nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }}
rp2040: ${{ steps.jsonStep.outputs.rp2040 }}
stm32: ${{ steps.jsonStep.outputs.stm32 }}
@@ -51,6 +59,7 @@ jobs:
matrix: ${{ fromJson(needs.setup.outputs.check) }}
runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v4
- name: Build base
@@ -86,6 +95,15 @@ jobs:
with:
board: ${{ matrix.board }}
build-esp32-c6:
needs: setup
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }}
uses: ./.github/workflows/build_esp32_c6.yml
with:
board: ${{ matrix.board }}
build-nrf52:
needs: setup
strategy:
@@ -119,11 +137,12 @@ jobs:
package-raspbian-armv7l:
uses: ./.github/workflows/package_raspbian_armv7l.yml
package-native:
uses: ./.github/workflows/package_amd64.yml
# package-native:
# uses: ./.github/workflows/package_amd64.yml
after-checks:
runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' }}
needs: [check]
steps:
- name: Checkout code
@@ -137,17 +156,17 @@ jobs:
contents: write
pull-requests: write
runs-on: ubuntu-latest
needs:
[
needs: [
build-esp32,
build-esp32-s3,
build-esp32-c3,
build-esp32-c6,
build-nrf52,
build-rpi2040,
build-stm32,
package-raspbian,
package-raspbian-armv7l,
package-native,
# package-native,
]
steps:
- name: Checkout code
@@ -216,22 +235,17 @@ jobs:
path: ./*.elf
retention-days: 30
- name: Create request artifacts
continue-on-error: true # FIXME: Why are we getting 502, but things still work?
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
uses: gavv/pull-request-artifacts@v2.1.0
- uses: scruplelesswizard/comment-artifact@main
if: ${{ github.event_name == 'pull_request' }}
with:
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
artifacts-token: ${{ secrets.ARTIFACTS_TOKEN }}
artifacts-repo: meshtastic/artifacts
artifacts-branch: device
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip
name: firmware-${{ steps.version.outputs.version }}
description: "Download firmware-${{ steps.version.outputs.version }}.zip. This artifact will be available for 90 days from creation"
github-token: ${{ secrets.GITHUB_TOKEN }}
release-artifacts:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' }}
needs: [gather-artifacts, after-checks]
needs: [gather-artifacts]
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -251,12 +265,6 @@ jobs:
merge-multiple: true
path: ./output
- uses: actions/download-artifact@v4
with:
pattern: meshtasticd_${{ steps.version.outputs.version }}_*.deb
merge-multiple: true
path: ./output
- name: Display structure of downloaded files
run: ls -R
@@ -266,7 +274,7 @@ jobs:
chmod +x ./output/device-update.sh
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output -x *.deb
run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output -x meshtasticd_*
- uses: actions/download-artifact@v4
with:
@@ -314,6 +322,12 @@ jobs:
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip
- uses: actions/download-artifact@v4
with:
pattern: meshtasticd_${{ steps.version.outputs.version }}_*.deb
merge-multiple: true
path: ./output
- name: Add raspbian aarch64 .deb
uses: actions/upload-release-asset@v1
env:
@@ -334,22 +348,50 @@ jobs:
asset_name: meshtasticd_${{ steps.version.outputs.version }}_armhf.deb
asset_content_type: application/vnd.debian.binary-package
- name: Add raspbian amd64 .deb
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./output/meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
asset_name: meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
asset_content_type: application/vnd.debian.binary-package
# - name: Add raspbian amd64 .deb
# uses: actions/upload-release-asset@v1
# env:
# GITHUB_TOKEN: ${{ github.token }}
# with:
# upload_url: ${{ steps.create_release.outputs.upload_url }}
# asset_path: ./output/meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
# asset_name: meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
# asset_content_type: application/vnd.debian.binary-package
- name: Bump version.properties
run: >-
bin/bump_version.py
- name: Create version.properties pull request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
title: Bump version.properties
add-paths: |
version.properties
- name: Checkout meshtastic/meshtastic.github.io
uses: actions/checkout@v4
with:
repository: meshtastic/meshtastic.github.io
token: ${{ secrets.ARTIFACTS_TOKEN }}
path: meshtastic.github.io
- name: Display structure of downloaded files
run: ls -R
- name: Extract firmware.zip
run: |
unzip ./firmware-${{ steps.version.outputs.version }}.zip -d meshtastic.github.io/firmware-${{ steps.version.outputs.version }}
- name: Display structure of downloaded files
run: ls -R
- name: Commit and push changes
run: |
cd meshtastic.github.io
find . -type f -name 'meshtasticd_*' -exec rm -f {} +
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "Add firmware version ${{ steps.version.outputs.version }}"
git push

View File

@@ -13,7 +13,7 @@ jobs:
uses: ./.github/workflows/build_native.yml
package-native:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs: build-native
steps:
- name: Checkout code

View File

@@ -13,7 +13,7 @@ jobs:
uses: ./.github/workflows/build_raspbian.yml
package-raspbian:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs: build-raspbian
steps:
- name: Checkout code

View File

@@ -13,7 +13,7 @@ jobs:
uses: ./.github/workflows/build_raspbian_armv7l.yml
package-raspbian_armv7l:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs: build-raspbian_armv7l
steps:
- name: Checkout code

View File

@@ -12,7 +12,7 @@ jobs:
semgrep-full:
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
image: semgrep/semgrep
steps:
# step 1

View File

@@ -4,9 +4,9 @@ on: pull_request
jobs:
semgrep-diff:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
container:
image: returntocorp/semgrep
image: semgrep/semgrep
steps:
# step 1

View File

@@ -57,35 +57,50 @@ jobs:
reporter: java-junit
hardware-tests:
runs-on: ubuntu-latest
runs-on: test-runner
steps:
- name: Checkout code
uses: actions/checkout@v4
# - uses: actions/setup-python@v5
# with:
# python-version: '3.10'
# pipx install "setuptools<72"
- name: Upgrade python tools
shell: bash
run: |
python -m pip install --upgrade pip
pip install -U --no-build-isolation --no-cache-dir "setuptools<72"
pip install -U platformio adafruit-nrfutil --no-build-isolation
pip install -U poetry --no-build-isolation
pip install -U meshtastic --pre --no-build-isolation
pipx install adafruit-nrfutil
pipx install poetry
pipx install meshtastic --pip-args=--pre
- name: Install PlatformIO from script
shell: bash
run: |
curl -fsSL -o get-platformio.py https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py
python3 get-platformio.py
- name: Upgrade platformio
shell: bash
run: |
export PATH=$PATH:$HOME/.local/bin
pio upgrade
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 18
- name: Setup pnpm
uses: pnpm/action-setup@v2
uses: pnpm/action-setup@v4
with:
version: latest
- name: Install Dependencies
run: pnpm install
- name: Setup devices
run: pnpm run setup
- name: Execute end to end tests on connected hardware
run: pnpm run test
- name: Install dependencies, setup devices and run
shell: bash
run: |
git submodule update --init --recursive
cd meshtestic/
pnpm install
pnpm run setup
pnpm run test

View File

@@ -1,4 +1,4 @@
name: "Update protobufs and regenerate classes"
name: Update protobufs and regenerate classes
on: workflow_dispatch
jobs:
@@ -26,8 +26,9 @@ jobs:
./bin/regen-protos.sh
- name: Create pull request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
title: Update protobufs and classes
add-paths: |
protobufs
src/mesh

View File

@@ -1,6 +1,6 @@
version: 0.1
cli:
version: 1.22.3
version: 1.22.5
plugins:
sources:
- id: trunk
@@ -8,27 +8,27 @@ plugins:
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- trufflehog@3.81.9
- trufflehog@3.82.5
- yamllint@1.35.1
- bandit@1.7.9
- checkov@3.2.238
- bandit@1.7.10
- checkov@3.2.255
- terrascan@1.19.1
- trivy@0.54.1
- trivy@0.55.2
#- trufflehog@3.63.2-rc0
- taplo@0.9.3
- ruff@0.6.2
- ruff@0.6.7
- isort@5.13.2
- markdownlint@0.41.0
- markdownlint@0.42.0
- oxipng@9.1.2
- svgo@3.3.2
- actionlint@1.7.1
- actionlint@1.7.2
- flake8@7.1.1
- hadolint@2.12.0
- shfmt@3.6.0
- shellcheck@0.10.0
- black@24.8.0
- git-diff-check
- gitleaks@8.18.4
- gitleaks@8.19.2
- clang-format@16.0.3
- prettier@3.3.3
ignore:

12
SECURITY.md Normal file
View File

@@ -0,0 +1,12 @@
# Security Policy
## Supported Versions
| Firmware Version | Supported |
| ---------------- | ------------------ |
| 2.5.x | :white_check_mark: |
| <= 2.4.x | :x: |
## Reporting a Vulnerability
We support the private reporting of potential security vulnerabilities. Please go to the Security tab to file a report with a description of the potential vulnerability and reproduction scripts (preferred) or steps, and our developers will review.

View File

@@ -5,7 +5,7 @@ custom_esp32_kind = esp32
platform = platformio/espressif32@6.7.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<mesh/raspihttp>
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
upload_speed = 921600
debug_init_break = tbreak setup

40
arch/esp32/esp32c6.ini Normal file
View File

@@ -0,0 +1,40 @@
[esp32c6_base]
extends = esp32_base
platform = https://github.com/Jason2866/platform-espressif32.git#22faa566df8c789000f8136cd8d0aca49617af55
build_flags =
${arduino_base.build_flags}
-Wall
-Wextra
-Isrc/platform/esp32
-std=c++11
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DSERIAL_BUFFER_SIZE=4096
-DLIBPAX_ARDUINO
-DLIBPAX_WIFI
-DLIBPAX_BLE
-DMESHTASTIC_EXCLUDE_WEBSERVER
;-DDEBUG_HEAP
; TEMP
-DHAS_BLUETOOTH=0
-DMESHTASTIC_EXCLUDE_PAXCOUNTER
-DMESHTASTIC_EXCLUDE_BLUETOOTH
lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
rweather/Crypto@^0.4.0
build_src_filter =
${esp32_base.build_src_filter} -<mesh/http>
monitor_speed = 460800
monitor_filters = esp32_c3_exception_decoder
lib_ignore =
NonBlockingRTTTL
NimBLE-Arduino
libpax

View File

@@ -16,7 +16,7 @@ build_flags =
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/> -<mesh/raspihttp>
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
lib_deps=
${arduino_base.lib_deps}

View File

@@ -1,6 +1,6 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
platform = https://github.com/meshtastic/platform-native.git#ad8112adf82ce1f5b917092cf32be07a077801a0
platform = https://github.com/meshtastic/platform-native.git#6b3796d697481c8f6e3f4aa5c111bd9979f29e64
framework = arduino
build_src_filter =
@@ -9,7 +9,7 @@ build_src_filter =
-<nimble/>
-<platform/nrf52/>
-<platform/stm32wl/>
-<platform/rp2040>
-<platform/rp2xx0>
-<mesh/wifi/>
-<mesh/http/>
+<mesh/raspihttp/>

View File

@@ -7,8 +7,8 @@ platform_packages = framework-arduinopico@https://github.com/earlephilhower/ardu
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
build_flags =
${arduino_base.build_flags} -Wno-unused-variable
-Isrc/platform/rp2040
${arduino_base.build_flags} -Wno-unused-variable -Wcast-align
-Isrc/platform/rp2xx0
-D__PLAT_RP2040__
# -D _POSIX_THREADS
build_src_filter =

23
arch/rp2xx0/rp2350.ini Normal file
View File

@@ -0,0 +1,23 @@
; Common settings for rp2040 Processor based targets
[rp2350_base]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#9e55f6db5c56b9867c69fe473f388beea4546672
extends = arduino_base
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#a6ab6e1f95bc1428d667d55ea7173c0744acc03c ; 4.0.2+
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
build_flags =
${arduino_base.build_flags} -Wno-unused-variable
-Isrc/platform/rp2xx0
-D__PLAT_RP2040__
# -D _POSIX_THREADS
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/> -<mesh/raspihttp>
lib_ignore =
BluetoothOTA
lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
rweather/Crypto

View File

@@ -22,7 +22,7 @@ build_flags =
-fdata-sections
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/RemoteHardwareModule.cpp> -<platform/nrf52> -<platform/portduino> -<platform/rp2040> -<mesh/raspihttp>
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/RemoteHardwareModule.cpp> -<platform/nrf52> -<platform/portduino> -<platform/rp2xx0> -<mesh/raspihttp>
board_upload.offset_address = 0x08000000
upload_protocol = stlink

View File

@@ -9,6 +9,7 @@ Lora:
# IRQ: 16
# Busy: 20
# Reset: 18
# SX126X_ANT_SW: 6
# Module: sx1262 # Waveshare SX1302 LISTEN ONLY AT THIS TIME!
# CS: 7
@@ -153,4 +154,4 @@ Webserver:
General:
MaxNodes: 200
MaxMessageQueue: 100
MaxMessageQueue: 100

View File

@@ -6,6 +6,7 @@ import configparser
import json
import os
import sys
import random
rootdir = "variants/"
@@ -39,5 +40,7 @@ for subdir, dirs, files in os.walk(rootdir):
"check" in options
):
outlist.append(section)
print(json.dumps(outlist))
if ("quick" in options) & (len(outlist) > 3):
print(json.dumps(random.sample(outlist, 3)))
else:
print(json.dumps(outlist))

View File

@@ -5,7 +5,7 @@
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA",
"extra_flags": "-DHELTEC_T114 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x4405"],

View File

@@ -1,40 +0,0 @@
{
"build": {
"arduino": {
"ldscript": "nrf52832_s132_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DNRF52832_XXAA -DNRF52",
"f_cpu": "64000000L",
"mcu": "nrf52832",
"variant": "lora_isp4520",
"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",
"openocd_target": "nrf52840-mdk-rs"
},
"frameworks": ["arduino"],
"name": "lora ISP4520",
"upload": {
"maximum_ram_size": 65536,
"maximum_size": 524288,
"require_upload_port": true,
"speed": 115200,
"protocol": "nrfutil",
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"]
},
"url": "",
"vendor": "PsiSoft"
}

View File

@@ -5,7 +5,7 @@
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA",
"extra_flags": "-DME25LS01_4Y10TD -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x8029"],

View File

@@ -5,7 +5,7 @@
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA",
"extra_flags": "-DMS24SF1 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x8029"],

View File

@@ -5,7 +5,7 @@
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
"extra_flags": "-DNORDIC_PCA10059 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x8029"],

View File

@@ -0,0 +1,42 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=0",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x1A86", "0x7523"]],
"mcu": "esp32s3",
"variant": "esp32s3r8"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino"],
"name": "Seeed Studio SenseCAP Indicator",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"speed": 921600
},
"url": "https://www.seeedstudio.com/Indicator-for-Meshtastic.html",
"vendor": "Seeed Studio"
}

41
boards/seeed-xiao-s3.json Normal file
View File

@@ -0,0 +1,41 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=0"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x2886", "0x0059"]],
"mcu": "esp32s3",
"variant": "seeed-xiao-s3"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "seeed-xiao-s3",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 8388608,
"maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://www.seeedstudio.com/XIAO-ESP32S3-Sense-p-5639.html",
"vendor": "Seeed Studio"
}

View File

@@ -60,35 +60,36 @@ build_flags = -Wno-missing-field-initializers
-DUSE_THREAD_NAMES
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
-DPB_ENABLE_MALLOC=1
-DRADIOLIB_EXCLUDE_CC1101
-DRADIOLIB_EXCLUDE_NRF24
-DRADIOLIB_EXCLUDE_RF69
-DRADIOLIB_EXCLUDE_SX1231
-DRADIOLIB_EXCLUDE_SX1233
-DRADIOLIB_EXCLUDE_SI443X
-DRADIOLIB_EXCLUDE_RFM2X
-DRADIOLIB_EXCLUDE_AFSK
-DRADIOLIB_EXCLUDE_BELL
-DRADIOLIB_EXCLUDE_HELLSCHREIBER
-DRADIOLIB_EXCLUDE_MORSE
-DRADIOLIB_EXCLUDE_RTTY
-DRADIOLIB_EXCLUDE_SSTV
-DRADIOLIB_EXCLUDE_AX25
-DRADIOLIB_EXCLUDE_DIRECT_RECEIVE
-DRADIOLIB_EXCLUDE_BELL
-DRADIOLIB_EXCLUDE_PAGER
-DRADIOLIB_EXCLUDE_FSK4
-DRADIOLIB_EXCLUDE_APRS
-DRADIOLIB_EXCLUDE_LORAWAN
-DRADIOLIB_EXCLUDE_CC1101=1
-DRADIOLIB_EXCLUDE_NRF24=1
-DRADIOLIB_EXCLUDE_RF69=1
-DRADIOLIB_EXCLUDE_SX1231=1
-DRADIOLIB_EXCLUDE_SX1233=1
-DRADIOLIB_EXCLUDE_SI443X=1
-DRADIOLIB_EXCLUDE_RFM2X=1
-DRADIOLIB_EXCLUDE_AFSK=1
-DRADIOLIB_EXCLUDE_BELL=1
-DRADIOLIB_EXCLUDE_HELLSCHREIBER=1
-DRADIOLIB_EXCLUDE_MORSE=1
-DRADIOLIB_EXCLUDE_RTTY=1
-DRADIOLIB_EXCLUDE_SSTV=1
-DRADIOLIB_EXCLUDE_AX25=1
-DRADIOLIB_EXCLUDE_DIRECT_RECEIVE=1
-DRADIOLIB_EXCLUDE_BELL=1
-DRADIOLIB_EXCLUDE_PAGER=1
-DRADIOLIB_EXCLUDE_FSK4=1
-DRADIOLIB_EXCLUDE_APRS=1
-DRADIOLIB_EXCLUDE_LORAWAN=1
-DMESHTASTIC_EXCLUDE_DROPZONE=1
-DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
-DBUILD_EPOCH=$UNIX_TIME
;-D OLED_PL
monitor_speed = 115200
monitor_filters = direct
lib_deps =
; jgromes/RadioLib@~6.6.0
https://github.com/jgromes/RadioLib.git#3115fc2d6700a9aee05888791ac930a910f2628f
jgromes/RadioLib@~7.0.2
https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95 ; ESP8266_SSD1306
https://github.com/mathertel/OneButton@~2.6.1 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
@@ -136,6 +137,7 @@ lib_deps =
adafruit/Adafruit MCP9808 Library@^2.0.0
adafruit/Adafruit INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0
adafruit/Adafruit MAX1704X@^1.0.3
adafruit/Adafruit SHTC3 Library@^1.0.0
adafruit/Adafruit LPS2X@^2.0.4
adafruit/Adafruit SHT31 Library@^2.2.2
@@ -148,16 +150,16 @@ lib_deps =
adafruit/Adafruit SHT4x Library@^1.0.4
adafruit/Adafruit TSL2591 Library@^1.4.5
sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@^1.0.5
sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@^1.2.13
ClosedCube OPT3001@^1.1.2
emotibit/EmotiBit MLX90632@^1.0.8
dfrobot/DFRobot_RTU@^1.0.3
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502
boschsensortec/BME68x Sensor Library@^1.1.40407
https://github.com/KodinLanewave/INA3221@^1.0.0
lewisxhe/SensorLib@^0.2.0
https://github.com/KodinLanewave/INA3221@^1.0.1
lewisxhe/SensorLib@0.2.0
mprograms/QMC5883LCompass@^1.2.0
https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee
https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee
https://github.com/gjelsoe/STK8xxx-Accelerometer.git#v0.1.1

View File

@@ -1,297 +0,0 @@
#pragma once
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
#include "PowerFSM.h"
#include "concurrency/OSThread.h"
#include "main.h"
#include "power.h"
#include <Adafruit_LIS3DH.h>
#include <Adafruit_LSM6DS3TRC.h>
#include <Adafruit_MPU6050.h>
#include <Arduino.h>
#include <SensorBMA423.hpp>
#include <Wire.h>
#ifdef RAK_4631
#include "Fusion/Fusion.h"
#include "graphics/Screen.h"
#include "graphics/ScreenFonts.h"
#include <Rak_BMX160.h>
#endif
#define ACCELEROMETER_CHECK_INTERVAL_MS 100
#define ACCELEROMETER_CLICK_THRESHOLD 40
static inline int readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
{
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom((uint8_t)address, (uint8_t)len);
uint8_t i = 0;
while (Wire.available()) {
data[i++] = Wire.read();
}
return 0; // Pass
}
static inline int writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
{
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(data, len);
return (0 != Wire.endTransmission());
}
class AccelerometerThread : public concurrency::OSThread
{
public:
explicit AccelerometerThread(ScanI2C::DeviceType type) : OSThread("AccelerometerThread")
{
if (accelerometer_found.port == ScanI2C::I2CPort::NO_I2C) {
LOG_DEBUG("AccelerometerThread disabling due to no sensors found\n");
disable();
return;
}
acceleremoter_type = type;
#ifndef RAK_4631
if (!config.display.wake_on_tap_or_motion && !config.device.double_tap_as_button_press) {
LOG_DEBUG("AccelerometerThread disabling due to no interested configurations\n");
disable();
return;
}
#endif
init();
}
void start()
{
init();
setIntervalFromNow(0);
};
protected:
int32_t runOnce() override
{
canSleep = true; // Assume we should not keep the board awake
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) {
wakeScreen();
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) {
uint8_t click = lis.getClick();
if (!config.device.double_tap_as_button_press) {
wakeScreen();
}
if (config.device.double_tap_as_button_press && (click & 0x20)) {
buttonPress();
return 500;
}
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.readIrqStatus() != DEV_WIRE_NONE) {
if (bmaSensor.isTilt() || bmaSensor.isDoubleTap()) {
wakeScreen();
return 500;
}
#ifdef RAK_4631
} else if (acceleremoter_type == ScanI2C::DeviceType::BMX160) {
sBmx160SensorData_t magAccel;
sBmx160SensorData_t gAccel;
/* Get a new sensor event */
bmx160.getAllData(&magAccel, NULL, &gAccel);
// expirimental calibrate routine. Limited to between 10 and 30 seconds after boot
if (millis() > 12 * 1000 && millis() < 30 * 1000) {
if (!showingScreen) {
showingScreen = true;
screen->startAlert((FrameCallback)drawFrameCalibration);
}
if (magAccel.x > highestX)
highestX = magAccel.x;
if (magAccel.x < lowestX)
lowestX = magAccel.x;
if (magAccel.y > highestY)
highestY = magAccel.y;
if (magAccel.y < lowestY)
lowestY = magAccel.y;
if (magAccel.z > highestZ)
highestZ = magAccel.z;
if (magAccel.z < lowestZ)
lowestZ = magAccel.z;
} else if (showingScreen && millis() >= 30 * 1000) {
showingScreen = false;
screen->endAlert();
}
int highestRealX = highestX - (highestX + lowestX) / 2;
magAccel.x -= (highestX + lowestX) / 2;
magAccel.y -= (highestY + lowestY) / 2;
magAccel.z -= (highestZ + lowestZ) / 2;
FusionVector ga, ma;
ga.axis.x = -gAccel.x; // default location for the BMX160 is on the rear of the board
ga.axis.y = -gAccel.y;
ga.axis.z = gAccel.z;
ma.axis.x = -magAccel.x;
ma.axis.y = -magAccel.y;
ma.axis.z = magAccel.z * 3;
// If we're set to one of the inverted positions
if (config.display.compass_orientation > meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270) {
ma = FusionAxesSwap(ma, FusionAxesAlignmentNXNYPZ);
ga = FusionAxesSwap(ga, FusionAxesAlignmentNXNYPZ);
}
float heading = FusionCompassCalculateHeading(FusionConventionNed, ga, ma);
switch (config.display.compass_orientation) {
case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0_INVERTED:
case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0:
break;
case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90:
case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90_INVERTED:
heading += 90;
break;
case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180:
case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180_INVERTED:
heading += 180;
break;
case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270:
case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED:
heading += 270;
break;
}
screen->setHeading(heading);
#endif
} else if (acceleremoter_type == ScanI2C::DeviceType::LSM6DS3 && lsm.shake()) {
wakeScreen();
return 500;
}
return ACCELEROMETER_CHECK_INTERVAL_MS;
}
private:
void init()
{
LOG_DEBUG("AccelerometerThread initializing\n");
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.begin(accelerometer_found.address)) {
LOG_DEBUG("MPU6050 initializing\n");
// setup motion detection
mpu.setHighPassFilter(MPU6050_HIGHPASS_0_63_HZ);
mpu.setMotionDetectionThreshold(1);
mpu.setMotionDetectionDuration(20);
mpu.setInterruptPinLatch(true); // Keep it latched. Will turn off when reinitialized.
mpu.setInterruptPinPolarity(true);
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.begin(accelerometer_found.address)) {
LOG_DEBUG("LIS3DH initializing\n");
lis.setRange(LIS3DH_RANGE_2_G);
// Adjust threshold, higher numbers are less sensitive
lis.setClick(config.device.double_tap_as_button_press ? 2 : 1, ACCELEROMETER_CLICK_THRESHOLD);
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 &&
bmaSensor.begin(accelerometer_found.address, &readRegister, &writeRegister)) {
LOG_DEBUG("BMA423 initializing\n");
bmaSensor.configAccelerometer(bmaSensor.RANGE_2G, bmaSensor.ODR_100HZ, bmaSensor.BW_NORMAL_AVG4,
bmaSensor.PERF_CONTINUOUS_MODE);
bmaSensor.enableAccelerometer();
bmaSensor.configInterrupt(BMA4_LEVEL_TRIGGER, BMA4_ACTIVE_HIGH, BMA4_PUSH_PULL, BMA4_OUTPUT_ENABLE,
BMA4_INPUT_DISABLE);
#ifdef BMA423_INT
pinMode(BMA4XX_INT, INPUT);
attachInterrupt(
BMA4XX_INT,
[] {
// Set interrupt to set irq value to true
BMA_IRQ = true;
},
RISING); // Select the interrupt mode according to the actual circuit
#endif
#ifdef T_WATCH_S3
// Need to raise the wrist function, need to set the correct axis
bmaSensor.setReampAxes(bmaSensor.REMAP_TOP_LAYER_RIGHT_CORNER);
#else
bmaSensor.setReampAxes(bmaSensor.REMAP_BOTTOM_LAYER_BOTTOM_LEFT_CORNER);
#endif
// bmaSensor.enableFeature(bmaSensor.FEATURE_STEP_CNTR, true);
bmaSensor.enableFeature(bmaSensor.FEATURE_TILT, true);
bmaSensor.enableFeature(bmaSensor.FEATURE_WAKEUP, true);
// bmaSensor.resetPedometer();
// Turn on feature interrupt
bmaSensor.enablePedometerIRQ();
bmaSensor.enableTiltIRQ();
// It corresponds to isDoubleClick interrupt
bmaSensor.enableWakeupIRQ();
#ifdef RAK_4631
} else if (acceleremoter_type == ScanI2C::DeviceType::BMX160 && bmx160.begin()) {
bmx160.ODR_Config(BMX160_ACCEL_ODR_100HZ, BMX160_GYRO_ODR_100HZ); // set output data rate
#endif
} else if (acceleremoter_type == ScanI2C::DeviceType::LSM6DS3 && lsm.begin_I2C(accelerometer_found.address)) {
LOG_DEBUG("LSM6DS3 initializing\n");
// Default threshold of 2G, less sensitive options are 4, 8 or 16G
lsm.setAccelRange(LSM6DS_ACCEL_RANGE_2_G);
#ifndef LSM6DS3_WAKE_THRESH
#define LSM6DS3_WAKE_THRESH 20
#endif
lsm.enableWakeup(config.display.wake_on_tap_or_motion, 1, LSM6DS3_WAKE_THRESH);
// Duration is number of occurances needed to trigger, higher threshold is less sensitive
}
}
void wakeScreen()
{
if (powerFSM.getState() == &stateDARK) {
LOG_INFO("Tap or motion detected. Turning on screen\n");
powerFSM.trigger(EVENT_INPUT);
}
}
void buttonPress()
{
LOG_DEBUG("Double-tap detected. Firing button press\n");
powerFSM.trigger(EVENT_PRESS);
}
ScanI2C::DeviceType acceleremoter_type;
Adafruit_MPU6050 mpu;
Adafruit_LIS3DH lis;
Adafruit_LSM6DS3TRC lsm;
SensorBMA423 bmaSensor;
bool BMA_IRQ = false;
#ifdef RAK_4631
bool showingScreen = false;
RAK_BMX160 bmx160;
float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0;
static void drawFrameCalibration(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
int x_offset = display->width() / 2;
int y_offset = display->height() <= 80 ? 0 : 32;
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_MEDIUM);
display->drawString(x, y, "Calibrating\nCompass");
int16_t compassX = 0, compassY = 0;
uint16_t compassDiam = graphics::Screen::getCompassDiam(display->getWidth(), display->getHeight());
// coordinates for the center of the compass/circle
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
compassX = x + display->getWidth() - compassDiam / 2 - 5;
compassY = y + display->getHeight() / 2;
} else {
compassX = x + display->getWidth() - compassDiam / 2 - 5;
compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2;
}
display->drawCircle(compassX, compassY, compassDiam / 2);
screen->drawCompassNorth(display, compassX, compassY, screen->getHeading() * PI / 180);
}
#endif
};
#endif

View File

@@ -124,6 +124,11 @@ int32_t ButtonThread::runOnce()
switch (btnEvent) {
case BUTTON_EVENT_PRESSED: {
LOG_BUTTON("press!\n");
// If a nag notification is running, stop it and prevent other actions
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
externalNotificationModule->stopNow();
return 50;
}
#ifdef BUTTON_PIN
if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
moduleConfig.canned_message.inputbroker_pin_press) ||

View File

@@ -370,8 +370,8 @@ void setupSDCard()
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
LOG_DEBUG("SD Card Size: %lluMB\n", cardSize);
LOG_DEBUG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
LOG_DEBUG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
LOG_DEBUG("SD Card Size: %lu MB\n", (uint32_t)cardSize);
LOG_DEBUG("Total space: %lu MB\n", (uint32_t)(SD.totalBytes() / (1024 * 1024)));
LOG_DEBUG("Used space: %lu MB\n", (uint32_t)(SD.usedBytes() / (1024 * 1024)));
#endif
}

View File

@@ -13,6 +13,7 @@
#include "power.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "Throttle.h"
#include "buzz/buzz.h"
#include "configuration.h"
#include "main.h"
@@ -30,6 +31,7 @@
#if HAS_WIFI
#include <WiFi.h>
#endif
#endif
#ifndef DELAY_FOREVER
@@ -75,6 +77,15 @@ INA219Sensor ina219Sensor;
INA3221Sensor ina3221Sensor;
#endif
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "modules/Telemetry/Sensor/MAX17048Sensor.h"
#include <utility>
extern std::pair<uint8_t, TwoWire *> nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1];
#if HAS_TELEMETRY && (!MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR || !MESHTASTIC_EXCLUDE_POWER_TELEMETRY)
MAX17048Sensor max17048Sensor;
#endif
#endif
#if HAS_RAKPROT && !defined(ARCH_PORTDUINO)
RAK9154Sensor rak9154Sensor;
#endif
@@ -136,6 +147,8 @@ using namespace meshtastic;
*/
static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level sensor
#ifdef BATTERY_PIN
static void adcEnable()
{
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
@@ -160,11 +173,14 @@ static void adcDisable()
#endif
}
#endif
/**
* A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input
*/
class AnalogBatteryLevel : public HasBatteryLevel
{
public:
/**
* Battery state of charge, from 0 to 100 or -1 for unknown
*/
@@ -244,7 +260,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
config.power.adc_multiplier_override > 0 ? config.power.adc_multiplier_override : ADC_MULTIPLIER;
// Do not call analogRead() often.
const uint32_t min_read_interval = 5000;
if (millis() - last_read_time_ms > min_read_interval) {
if (!Throttle::isWithinTimespanMs(last_read_time_ms, min_read_interval)) {
last_read_time_ms = millis();
uint32_t raw = 0;
@@ -551,7 +567,12 @@ bool Power::analogInit()
*/
bool Power::setup()
{
bool found = axpChipInit() || analogInit();
// initialise one power sensor (only)
bool found = axpChipInit();
if (!found)
found = lipoInit();
if (!found)
found = analogInit();
#ifdef NRF_APM
found = true;
@@ -1042,4 +1063,82 @@ bool Power::axpChipInit()
#else
return false;
#endif
}
}
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
/**
* Wrapper class for an I2C MAX17048 Lipo battery sensor.
*/
class LipoBatteryLevel : public HasBatteryLevel
{
private:
MAX17048Singleton *max17048 = nullptr;
public:
/**
* Init the I2C MAX17048 Lipo battery level sensor
*/
bool runOnce()
{
if (max17048 == nullptr) {
max17048 = MAX17048Singleton::GetInstance();
}
// try to start if the sensor has been detected
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MAX17048].first != 0) {
return max17048->runOnce(nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MAX17048].second);
}
return false;
}
/**
* Battery state of charge, from 0 to 100 or -1 for unknown
*/
virtual int getBatteryPercent() override { return max17048->getBusBatteryPercent(); }
/**
* The raw voltage of the battery in millivolts, or NAN if unknown
*/
virtual uint16_t getBattVoltage() override { return max17048->getBusVoltageMv(); }
/**
* return true if there is a battery installed in this unit
*/
virtual bool isBatteryConnect() override { return max17048->isBatteryConnected(); }
/**
* return true if there is an external power source detected
*/
virtual bool isVbusIn() override { return max17048->isExternallyPowered(); }
/**
* return true if the battery is currently charging
*/
virtual bool isCharging() override { return max17048->isBatteryCharging(); }
};
LipoBatteryLevel lipoLevel;
/**
* Init the Lipo battery level sensor
*/
bool Power::lipoInit()
{
bool result = lipoLevel.runOnce();
LOG_DEBUG("Power::lipoInit lipo sensor is %s\n", result ? "ready" : "not ready yet");
if (!result)
return false;
batteryLevel = &lipoLevel;
return true;
}
#else
/**
* The Lipo battery level sensor is unavailable - default to AnalogBatteryLevel
*/
bool Power::lipoInit()
{
return false;
}
#endif

View File

@@ -24,7 +24,7 @@
class SafeFile : public Print
{
public:
SafeFile(char const *filepath, bool fullAtomic = false);
explicit SafeFile(char const *filepath, bool fullAtomic = false);
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buffer, size_t size);

View File

@@ -1,6 +1,8 @@
#include "SerialConsole.h"
#include "Default.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "Throttle.h"
#include "configuration.h"
#include "time.h"
@@ -44,10 +46,11 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
Port.setRX(SERIAL2_RX);
#endif
Port.begin(SERIAL_BAUD);
#if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(ARCH_RP2040)
#if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(ARCH_RP2040) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
time_t timeout = millis();
while (!Port) {
if ((millis() - timeout) < 5000) {
if (Throttle::isWithinTimespanMs(timeout, FIVE_SECONDS_MS)) {
delay(100);
} else {
break;
@@ -72,8 +75,7 @@ void SerialConsole::flush()
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
bool SerialConsole::checkIsConnected()
{
uint32_t now = millis();
return (now - lastContactMsec) < SERIAL_CONNECTION_TIMEOUT;
return Throttle::isWithinTimespanMs(lastContactMsec, SERIAL_CONNECTION_TIMEOUT);
}
/**
@@ -120,4 +122,4 @@ void SerialConsole::log_to_serial(const char *logLevel, const char *format, va_l
emitLogRecord(ll, thread ? thread->ThreadName.c_str() : "", format, arg);
} else
RedirectablePrint::log_to_serial(logLevel, format, arg);
}
}

View File

@@ -69,6 +69,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef RTC_DATA_ATTR
#define RTC_DATA_ATTR
#endif
#ifndef EXT_RAM_BSS_ATTR
#define EXT_RAM_BSS_ATTR EXT_RAM_ATTR
#endif
// -----------------------------------------------------------------------------
// Regulatory overrides
@@ -122,9 +125,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define INA_ADDR_ALTERNATE 0x41
#define INA_ADDR_WAVESHARE_UPS 0x43
#define INA3221_ADDR 0x42
#define MAX1704X_ADDR 0x36
#define QMC6310_ADDR 0x1C
#define QMI8658_ADDR 0x6B
#define QMC5883L_ADDR 0x1E
#define QMC5883L_ADDR 0x0D
#define HMC5883L_ADDR 0x1E
#define SHTC3_ADDR 0x70
#define LPS22HB_ADDR 0x5C
#define LPS22HB_ADDR_ALT 0x5D
@@ -144,10 +149,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// ACCELEROMETER
// -----------------------------------------------------------------------------
#define MPU6050_ADDR 0x68
#define STK8BXX_ADR 0x18
#define LIS3DH_ADR 0x18
#define BMA423_ADDR 0x19
#define LSM6DS3_ADDR 0x6A
#define BMX160_ADDR 0x69
#define ICM20948_ADDR 0x69
#define ICM20948_ADDR_ALT 0x68
// -----------------------------------------------------------------------------
// LED
@@ -162,6 +170,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
// IO Expander
// -----------------------------------------------------------------------------
#define TCA9535_ADDR 0x20
#define TCA9555_ADDR 0x26
// -----------------------------------------------------------------------------
@@ -171,6 +180,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define GPS_THREAD_INTERVAL 200
#endif
// -----------------------------------------------------------------------------
// Touchscreen
// -----------------------------------------------------------------------------
#define FT6336U_ADDR 0x48
// convert 24-bit color to 16-bit (56K)
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
@@ -202,6 +216,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MINIMUM_SAFE_FREE_HEAP 1500
#endif
#ifndef WIRE_INTERFACES_COUNT
// Officially an NRF52 macro
// Repurposed cross-platform to identify devices using Wire1
#if defined(I2C_SDA1) || defined(PIN_WIRE1_SDA)
#define WIRE_INTERFACES_COUNT 2
#elif HAS_WIRE
#define WIRE_INTERFACES_COUNT 1
#endif
#endif
/* Step #3: mop up with disabled values for HAS_ options not handled by the above two */
#ifndef HAS_WIFI
@@ -324,4 +348,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#include "DebugConfiguration.h"
#include "RF95Configuration.h"
#include "RF95Configuration.h"

View File

@@ -10,7 +10,8 @@ enum LoRaRadioType {
LLCC68_RADIO,
SX1280_RADIO,
LR1110_RADIO,
LR1120_RADIO
LR1120_RADIO,
LR1121_RADIO
};
extern LoRaRadioType radioType;

View File

@@ -37,8 +37,8 @@ ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
{
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160};
return firstOfOrNONE(5, types);
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948};
return firstOfOrNONE(7, types);
}
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const

View File

@@ -28,6 +28,7 @@ class ScanI2C
INA260,
INA219,
INA3221,
MAX17048,
MCP9808,
SHT31,
SHT4X,
@@ -36,12 +37,14 @@ class ScanI2C
QMC6310,
QMI8658,
QMC5883L,
HMC5883L,
PMSA0031,
MPU6050,
LIS3DH,
BMA423,
BQ24295,
LSM6DS3,
TCA9535,
TCA9555,
VEML7700,
RCWL9620,
@@ -52,7 +55,10 @@ class ScanI2C
AHT10,
BMX160,
DFROBOT_LARK,
NAU7802
NAU7802,
FT6336U,
STK8BAXX,
ICM20948
} DeviceType;
// typedef uint8_t DeviceAddress;
@@ -63,8 +69,9 @@ class ScanI2C
} I2CPort;
typedef struct DeviceAddress {
I2CPort port;
uint8_t address;
// set default values for ADDRESS_NONE
I2CPort port = I2CPort::NO_I2C;
uint8_t address = 0;
explicit DeviceAddress(I2CPort port, uint8_t address);
DeviceAddress();

View File

@@ -162,13 +162,13 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
Melopero_RV3028 rtc;
#endif
#ifdef I2C_SDA1
#if WIRE_INTERFACES_COUNT == 2
if (port == I2CPort::WIRE1) {
i2cBus = &Wire1;
} else {
#endif
i2cBus = &Wire;
#ifdef I2C_SDA1
#if WIRE_INTERFACES_COUNT == 2
}
#endif
@@ -313,17 +313,33 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
break;
case MCP9808_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
if (registerValue == 0x0400) {
type = MCP9808;
LOG_INFO("MCP9808 sensor found\n");
} else {
type = LIS3DH;
LOG_INFO("LIS3DH accelerometer found\n");
// We need to check for STK8BAXX first, since register 0x07 is new data flag for the z-axis and can produce some
// weird result. and register 0x00 doesn't seems to be colliding with MCP9808 and LIS3DH chips.
{
// Check register 0x00 for 0x8700 response to ID STK8BA53 chip.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 2);
if (registerValue == 0x8700) {
type = STK8BAXX;
LOG_INFO("STK8BAXX accelerometer found\n");
break;
}
// Check register 0x07 for 0x0400 response to ID MCP9808 chip.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
if (registerValue == 0x0400) {
type = MCP9808;
LOG_INFO("MCP9808 sensor found\n");
break;
}
// Check register 0x0F for 0x3300 response to ID LIS3DH chip.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2);
if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333
type = LIS3DH;
LOG_INFO("LIS3DH accelerometer found\n");
}
break;
}
break;
case SHT31_4x_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c) {
@@ -365,18 +381,37 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found\n")
SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L 3-Axis digital compass found\n")
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n")
SCAN_SIMPLE_CASE(MPU6050_ADDR, MPU6050, "MPU6050 accelerometer found\n");
SCAN_SIMPLE_CASE(BMX160_ADDR, BMX160, "BMX160 accelerometer found\n");
SCAN_SIMPLE_CASE(BMA423_ADDR, BMA423, "BMA423 accelerometer found\n");
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3 accelerometer found at address 0x%x\n", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535 I2C expander found\n");
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555 I2C expander found\n");
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700 light sensor found\n");
SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591 light sensor found\n");
SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001 light sensor found\n");
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632 IR temp sensor found\n");
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802 based scale found\n");
SCAN_SIMPLE_CASE(FT6336U_ADDR, FT6336U, "FT6336U touchscreen found\n");
SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048 lipo fuel gauge found\n");
case ICM20948_ADDR: // same as BMX160_ADDR
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
if (registerValue == 0xEA) {
type = ICM20948;
LOG_INFO("ICM20948 9-dof motion processor found\n");
break;
} else if (addr.address == BMX160_ADDR) {
type = BMX160;
LOG_INFO("BMX160 accelerometer found\n");
break;
} else {
type = MPU6050;
LOG_INFO("MPU6050 accelerometer found\n");
break;
}
break;
default:
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
@@ -403,7 +438,7 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
if (address.port == ScanI2C::I2CPort::WIRE) {
return &Wire;
} else {
#ifdef I2C_SDA1
#if WIRE_INTERFACES_COUNT == 2
return &Wire1;
#else
return &Wire;
@@ -415,4 +450,4 @@ size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
}
#endif
#endif

View File

@@ -6,6 +6,8 @@
#include "NodeDB.h"
#include "PowerMon.h"
#include "RTC.h"
#include "Throttle.h"
#include "meshUtils.h"
#include "main.h" // pmu_found
#include "sleep.h"
@@ -26,6 +28,8 @@
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
HardwareSerial *GPS::_serial_gps = &Serial1;
#elif defined(ARCH_RP2040)
SerialUART *GPS::_serial_gps = &Serial1;
#else
HardwareSerial *GPS::_serial_gps = NULL;
#endif
@@ -58,7 +62,8 @@ const char *getGPSPowerStateString(GPSPowerState state)
case GPS_OFF:
return "OFF";
default:
assert(false); // Unhandled enum value..
assert(false); // Unhandled enum value..
return "FALSE"; // to make new ESP-IDF happy
}
}
@@ -86,9 +91,9 @@ void GPS::CASChecksum(uint8_t *message, size_t length)
// Iterate over the payload as a series of uint32_t's and
// accumulate the cksum
uint32_t const *payload = (uint32_t *)(message + 6);
for (size_t i = 0; i < (length - 10) / 4; i++) {
uint32_t pl = payload[i];
uint32_t pl = 0;
memcpy(&pl, (message + 6) + (i * sizeof(uint32_t)), sizeof(uint32_t)); // avoid pointer dereference
cksum += pl;
}
@@ -166,18 +171,21 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
b = _serial_gps->read();
#ifdef GPS_DEBUG
LOG_DEBUG("%02X", (char *)buffer);
LOG_DEBUG("%c", (b >= 32 && b <= 126) ? b : '.');
#endif
buffer[bytesRead] = b;
bytesRead++;
if ((bytesRead == 767) || (b == '\r')) {
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
#ifdef GPS_DEBUG
LOG_DEBUG("\r");
LOG_DEBUG("\r\nFound: %s\r\n", message); // Log the found message
#endif
return GNSS_RESPONSE_OK;
} else {
bytesRead = 0;
#ifdef GPS_DEBUG
LOG_DEBUG("\r\n");
#endif
}
}
}
@@ -201,7 +209,7 @@ GPS_RESPONSE GPS::getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMilli
// ACK-NACK| 0xBA | 0xCE | 0x04 | 0x00 | 0x05 | 0x00 | 0xXX | 0xXX | 0x00 | 0x00 | 0xXX | 0xXX | 0xXX | 0xXX |
// ACK-ACK | 0xBA | 0xCE | 0x04 | 0x00 | 0x05 | 0x01 | 0xXX | 0xXX | 0x00 | 0x00 | 0xXX | 0xXX | 0xXX | 0xXX |
while (millis() - startTime < waitMillis) {
while (Throttle::isWithinTimespanMs(startTime, waitMillis)) {
if (_serial_gps->available()) {
buffer[bufferPos++] = _serial_gps->read();
@@ -270,7 +278,7 @@ GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
buf[9] += buf[8];
}
while (millis() - startTime < waitMillis) {
while (Throttle::isWithinTimespanMs(startTime, waitMillis)) {
if (ack > 9) {
#ifdef GPS_DEBUG
LOG_DEBUG("\n");
@@ -325,9 +333,9 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
{
uint16_t ubxFrameCounter = 0;
uint32_t startTime = millis();
uint16_t needRead;
uint16_t needRead = 0;
while (millis() - startTime < waitMillis) {
while (Throttle::isWithinTimespanMs(startTime, waitMillis)) {
if (_serial_gps->available()) {
int c = _serial_gps->read();
switch (ubxFrameCounter) {
@@ -398,9 +406,9 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
bool GPS::setup()
{
int msglen = 0;
if (!didSerialInit) {
int msglen = 0;
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
// if GPS_BAUDRATE is specified in variant (i.e. not 9600), skip to the specified rate.
@@ -505,283 +513,110 @@ bool GPS::setup()
delay(250);
_serial_gps->write("$CFGMSG,6,1,0\r\n");
delay(250);
} else if (gnssModel == GNSS_MODEL_AG3335) {
} else if (IS_ONE_OF(gnssModel, GNSS_MODEL_AG3335, GNSS_MODEL_AG3352)) {
_serial_gps->write("$PAIR066,1,0,1,0,0,1*3B\r\n"); // Enable GPS+GALILEO+NAVIC
// Configure NMEA (sentences will output once per fix)
_serial_gps->write("$PAIR062,0,0*3F\r\n"); // GGA ON
_serial_gps->write("$PAIR062,0,1*3F\r\n"); // GGA ON
_serial_gps->write("$PAIR062,1,0*3F\r\n"); // GLL OFF
_serial_gps->write("$PAIR062,2,1*3D\r\n"); // GSA ON
_serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF
_serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF
_serial_gps->write("$PAIR062,4,0*3B\r\n"); // RMC ON
_serial_gps->write("$PAIR062,4,1*3B\r\n"); // RMC ON
_serial_gps->write("$PAIR062,5,0*3B\r\n"); // VTG OFF
_serial_gps->write("$PAIR062,6,1*39\r\n"); // ZDA ON
_serial_gps->write("$PAIR062,6,0*38\r\n"); // ZDA ON
delay(250);
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration
} else if (gnssModel == GNSS_MODEL_UBLOX6) {
clearBuffer();
SEND_UBX_PACKET(0x06, 0x02, _message_DISABLE_TXT_INFO, "Unable to disable text info messages.\n", 500);
SEND_UBX_PACKET(0x06, 0x39, _message_JAM_6_7, "Unable to enable interference resistance.\n", 500);
SEND_UBX_PACKET(0x06, 0x23, _message_NAVX5, "Unable to configure NAVX5 settings.\n", 500);
} else if (gnssModel == GNSS_MODEL_UBLOX) {
// Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command)
// We need set it because by default it is GPS only, and we want to use GLONASS too
// Also we need SBAS for better accuracy and extra features
// ToDo: Dynamic configure GNSS systems depending of LoRa region
// Turn off unwanted NMEA messages, set update rate
SEND_UBX_PACKET(0x06, 0x08, _message_1HZ, "Unable to set GPS update rate.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_GLL, "Unable to disable NMEA GLL.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_GSA, "Unable to Enable NMEA GSA.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_GSV, "Unable to disable NMEA GSV.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_VTG, "Unable to disable NMEA VTG.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_RMC, "Unable to enable NMEA RMC.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_GGA, "Unable to enable NMEA GGA.\n", 500);
if (strncmp(info.hwVersion, "000A0000", 8) != 0) {
if (strncmp(info.hwVersion, "00040007", 8) != 0) {
// The original ublox Neo-6 is GPS only and doesn't support the UBX-CFG-GNSS message
// Max7 seems to only support GPS *or* GLONASS
// Neo-7 is supposed to support GPS *and* GLONASS but NAKs the CFG-GNSS command to do it
// So treat all the u-blox 7 series as GPS only
// M8 can support 3 constallations at once so turn on GPS, GLONASS and Galileo (or BeiDou)
clearBuffer();
SEND_UBX_PACKET(0x06, 0x11, _message_CFG_RXM_ECO, "Unable to enable powersaving ECO mode for Neo-6.\n", 500);
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "Unable to enable powersaving details for GPS.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_AID, "Unable to disable UBX-AID.\n", 500);
if (strncmp(info.hwVersion, "00070000", 8) == 0) {
LOG_DEBUG("Setting GPS+SBAS\n");
msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_7), _message_GNSS_7);
_serial_gps->write(UBXscratch, msglen);
} else {
msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_8), _message_GNSS_8);
_serial_gps->write(UBXscratch, msglen);
}
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x09, 2000) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to save GNSS module configuration.\n");
} else {
LOG_INFO("GNSS module configuration saved!\n");
}
} else if (IS_ONE_OF(gnssModel, GNSS_MODEL_UBLOX7, GNSS_MODEL_UBLOX8, GNSS_MODEL_UBLOX9)) {
if (gnssModel == GNSS_MODEL_UBLOX7) {
LOG_DEBUG("Setting GPS+SBAS\n");
msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_7), _message_GNSS_7);
_serial_gps->write(UBXscratch, msglen);
} else { // 8,9
msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_8), _message_GNSS_8);
_serial_gps->write(UBXscratch, msglen);
}
if (getACK(0x06, 0x3e, 800) == GNSS_RESPONSE_NAK) {
// It's not critical if the module doesn't acknowledge this configuration.
LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n");
} else {
if (strncmp(info.hwVersion, "00070000", 8) == 0) {
LOG_INFO("GNSS configured for GPS+SBAS. Pause for 0.75s before sending next command.\n");
} else {
LOG_INFO(
"GNSS configured for GPS+SBAS+GLONASS+Galileo. Pause for 0.75s before sending next command.\n");
}
// Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next
// commands for the M8 it tends to be more... 1 sec should be enough ;>)
delay(1000);
}
if (getACK(0x06, 0x3e, 800) == GNSS_RESPONSE_NAK) {
// It's not critical if the module doesn't acknowledge this configuration.
LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n");
} else {
if (gnssModel == GNSS_MODEL_UBLOX7) {
LOG_INFO("GNSS configured for GPS+SBAS.\n");
} else { // 8,9
LOG_INFO("GNSS configured for GPS+SBAS+GLONASS+Galileo.\n");
}
// Disable Text Info messages
msglen = makeUBXPacket(0x06, 0x02, sizeof(_message_DISABLE_TXT_INFO), _message_DISABLE_TXT_INFO);
// Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next
// commands for the M8 it tends to be more... 1 sec should be enough ;>)
delay(1000);
}
// Disable Text Info messages //6,7,8,9
clearBuffer();
SEND_UBX_PACKET(0x06, 0x02, _message_DISABLE_TXT_INFO, "Unable to disable text info messages.\n", 500);
if (gnssModel == GNSS_MODEL_UBLOX8) { // 8
clearBuffer();
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x02, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable text info messages.\n");
}
// ToDo add M10 tests for below
if (strncmp(info.hwVersion, "00080000", 8) == 0) {
msglen = makeUBXPacket(0x06, 0x39, sizeof(_message_JAM_8), _message_JAM_8);
SEND_UBX_PACKET(0x06, 0x39, _message_JAM_8, "Unable to enable interference resistance.\n", 500);
clearBuffer();
SEND_UBX_PACKET(0x06, 0x23, _message_NAVX5_8, "Unable to configure NAVX5_8 settings.\n", 500);
} else { // 6,7,9
SEND_UBX_PACKET(0x06, 0x39, _message_JAM_6_7, "Unable to enable interference resistance.\n", 500);
SEND_UBX_PACKET(0x06, 0x23, _message_NAVX5, "Unable to configure NAVX5 settings.\n", 500);
}
// Turn off unwanted NMEA messages, set update rate
SEND_UBX_PACKET(0x06, 0x08, _message_1HZ, "Unable to set GPS update rate.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_GLL, "Unable to disable NMEA GLL.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_GSA, "Unable to Enable NMEA GSA.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_GSV, "Unable to disable NMEA GSV.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_VTG, "Unable to disable NMEA VTG.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_RMC, "Unable to enable NMEA RMC.\n", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_GGA, "Unable to enable NMEA GGA.\n", 500);
if (uBloxProtocolVersion >= 18) {
clearBuffer();
SEND_UBX_PACKET(0x06, 0x86, _message_PMS, "Unable to enable powersaving for GPS.\n", 500);
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "Unable to enable powersaving details for GPS.\n", 500);
// For M8 we want to enable NMEA vserion 4.10 so we can see the additional sats.
if (gnssModel == GNSS_MODEL_UBLOX8) {
clearBuffer();
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x39, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable interference resistance.\n");
}
msglen = makeUBXPacket(0x06, 0x23, sizeof(_message_NAVX5_8), _message_NAVX5_8);
clearBuffer();
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x23, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to configure NAVX5_8 settings.\n");
}
} else {
msglen = makeUBXPacket(0x06, 0x39, sizeof(_message_JAM_6_7), _message_JAM_6_7);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x39, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable interference resistance.\n");
}
msglen = makeUBXPacket(0x06, 0x23, sizeof(_message_NAVX5), _message_NAVX5);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x23, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to configure NAVX5 settings.\n");
}
}
// Turn off unwanted NMEA messages, set update rate
msglen = makeUBXPacket(0x06, 0x08, sizeof(_message_1HZ), _message_1HZ);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x08, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to set GPS update rate.\n");
}
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GLL), _message_GLL);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable NMEA GLL.\n");
}
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GSA), _message_GSA);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to Enable NMEA GSA.\n");
}
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GSV), _message_GSV);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable NMEA GSV.\n");
}
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_VTG), _message_VTG);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable NMEA VTG.\n");
}
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_RMC), _message_RMC);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable NMEA RMC.\n");
}
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GGA), _message_GGA);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable NMEA GGA.\n");
}
if (uBloxProtocolVersion >= 18) {
msglen = makeUBXPacket(0x06, 0x86, sizeof(_message_PMS), _message_PMS);
clearBuffer();
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x86, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving for GPS.\n");
}
msglen = makeUBXPacket(0x06, 0x3B, sizeof(_message_CFG_PM2), _message_CFG_PM2);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x3B, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving details for GPS.\n");
}
// For M8 we want to enable NMEA vserion 4.10 so we can see the additional sats.
if (strncmp(info.hwVersion, "00080000", 8) == 0) {
msglen = makeUBXPacket(0x06, 0x17, sizeof(_message_NMEA), _message_NMEA);
clearBuffer();
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x17, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable NMEA 4.10.\n");
}
}
} else {
if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode is only for Neo-6
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x11, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving ECO mode for Neo-6.\n");
}
msglen = makeUBXPacket(0x06, 0x3B, sizeof(_message_CFG_PM2), _message_CFG_PM2);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x3B, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving details for GPS.\n");
}
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_AID), _message_AID);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable UBX-AID.\n");
}
} else {
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x11, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving mode for GPS.\n");
}
msglen = makeUBXPacket(0x06, 0x3B, sizeof(_message_CFG_PM2), _message_CFG_PM2);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x3B, 500) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving details for GPS.\n");
}
}
SEND_UBX_PACKET(0x06, 0x17, _message_NMEA, "Unable to enable NMEA 4.10.\n", 500);
}
} else {
// LOG_INFO("u-blox M10 hardware found.\n");
delay(1000);
// First disable all NMEA messages in RAM layer
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_NMEA_RAM), _message_VALSET_DISABLE_NMEA_RAM);
clearBuffer();
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable NMEA messages for M10 GPS RAM.\n");
}
delay(250);
// Next disable unwanted NMEA messages in BBR layer
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_NMEA_BBR), _message_VALSET_DISABLE_NMEA_BBR);
clearBuffer();
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable NMEA messages for M10 GPS BBR.\n");
}
delay(250);
// Disable Info txt messages in RAM layer
msglen =
makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_TXT_INFO_RAM), _message_VALSET_DISABLE_TXT_INFO_RAM);
clearBuffer();
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable Info messages for M10 GPS RAM.\n");
}
delay(250);
// Next disable Info txt messages in BBR layer
msglen =
makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_TXT_INFO_BBR), _message_VALSET_DISABLE_TXT_INFO_BBR);
clearBuffer();
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable Info messages for M10 GPS BBR.\n");
}
// Do M10 configuration for Power Management.
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_PM_RAM), _message_VALSET_PM_RAM);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving for M10 GPS RAM.\n");
}
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_PM_BBR), _message_VALSET_PM_BBR);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving for M10 GPS BBR.\n");
}
delay(250);
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_ITFM_RAM), _message_VALSET_ITFM_RAM);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable Jamming detection M10 GPS RAM.\n");
}
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_ITFM_BBR), _message_VALSET_ITFM_BBR);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable Jamming detection M10 GPS BBR.\n");
}
// Here is where the init commands should go to do further M10 initialization.
delay(250);
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_SBAS_RAM), _message_VALSET_DISABLE_SBAS_RAM);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable SBAS M10 GPS RAM.\n");
}
delay(750); // will cause a receiver restart so wait a bit
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_SBAS_BBR), _message_VALSET_DISABLE_SBAS_BBR);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable SBAS M10 GPS BBR.\n");
}
delay(750); // will cause a receiver restart so wait a bit
// Done with initialization, Now enable wanted NMEA messages in BBR layer so they will survive a periodic sleep.
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_ENABLE_NMEA_BBR), _message_VALSET_ENABLE_NMEA_BBR);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable messages for M10 GPS BBR.\n");
}
delay(250);
// Next enable wanted NMEA messages in RAM layer
msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_ENABLE_NMEA_RAM), _message_VALSET_ENABLE_NMEA_RAM);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable messages for M10 GPS RAM.\n");
}
// As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR.
// BBR will survive a restart, and power off for a while, but modules with small backup
// batteries or super caps will not retain the config for a long power off time.
SEND_UBX_PACKET(0x06, 0x11, _message_CFG_RXM_PSM, "Unable to enable powersaving mode for GPS.\n", 500);
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "Unable to enable powersaving details for GPS.\n", 500);
}
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x09, 2000) != GNSS_RESPONSE_OK) {
@@ -789,6 +624,55 @@ bool GPS::setup()
} else {
LOG_INFO("GNSS module configuration saved!\n");
}
} else if (gnssModel == GNSS_MODEL_UBLOX10) {
delay(1000);
clearBuffer();
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_NMEA_RAM, "Unable to disable NMEA messages in M10 RAM.\n", 300);
delay(750);
clearBuffer();
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_NMEA_BBR, "Unable to disable NMEA messages in M10 BBR.\n", 300);
delay(750);
clearBuffer();
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_TXT_INFO_RAM,
"Unable to disable Info messages for M10 GPS RAM.\n", 300);
delay(750);
// Next disable Info txt messages in BBR layer
clearBuffer();
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_TXT_INFO_BBR,
"Unable to disable Info messages for M10 GPS BBR.\n", 300);
delay(750);
// Do M10 configuration for Power Management.
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_PM_RAM, "Unable to enable powersaving for M10 GPS RAM.\n", 300);
delay(750);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_PM_BBR, "Unable to enable powersaving for M10 GPS BBR.\n", 300);
delay(750);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ITFM_RAM, "Unable to enable Jamming detection M10 GPS RAM.\n", 300);
delay(750);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ITFM_BBR, "Unable to enable Jamming detection M10 GPS BBR.\n", 300);
delay(750);
// Here is where the init commands should go to do further M10 initialization.
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_SBAS_RAM, "Unable to disable SBAS M10 GPS RAM.\n", 300);
delay(750); // will cause a receiver restart so wait a bit
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_SBAS_BBR, "Unable to disable SBAS M10 GPS BBR.\n", 300);
delay(750); // will cause a receiver restart so wait a bit
// Done with initialization, Now enable wanted NMEA messages in BBR layer so they will survive a periodic sleep.
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ENABLE_NMEA_BBR, "Unable to enable messages for M10 GPS BBR.\n", 300);
delay(750);
// Next enable wanted NMEA messages in RAM layer
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ENABLE_NMEA_RAM, "Unable to enable messages for M10 GPS RAM.\n", 500);
delay(750);
// As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR.
// BBR will survive a restart, and power off for a while, but modules with small backup
// batteries or super caps will not retain the config for a long power off time.
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE_10), _message_SAVE_10);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x09, 2000) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to save GNSS module configuration.\n");
} else {
LOG_INFO("GNSS module configuration saved!\n");
}
}
didSerialInit = true;
}
@@ -944,7 +828,7 @@ void GPS::setPowerPMU(bool on)
void GPS::setPowerUBLOX(bool on, uint32_t sleepMs)
{
// Abort: if not UBLOX hardware
if (gnssModel != GNSS_MODEL_UBLOX)
if (!IS_ONE_OF(gnssModel, GNSS_MODEL_UBLOX6, GNSS_MODEL_UBLOX7, GNSS_MODEL_UBLOX8, GNSS_MODEL_UBLOX9, GNSS_MODEL_UBLOX10))
return;
// If waking
@@ -967,7 +851,7 @@ void GPS::setPowerUBLOX(bool on, uint32_t sleepMs)
}
// Determine hardware version
if (strncmp(info.hwVersion, "000A0000", 8) != 0) {
if (gnssModel == GNSS_MODEL_UBLOX10) {
// Encode the sleep time in millis into the packet
for (int i = 0; i < 4; i++)
gps->_message_PMREQ[0 + i] = sleepMs >> (i * 8);
@@ -1026,26 +910,29 @@ void GPS::down()
// Check whether the GPS hardware is capable of GPS_SOFTSLEEP
// If not, fallback to GPS_HARDSLEEP instead
bool softsleepSupported = false;
if (gnssModel == GNSS_MODEL_UBLOX) // U-blox is supported via PMREQ
// U-blox is supported via PMREQ
if (IS_ONE_OF(gnssModel, GNSS_MODEL_UBLOX6, GNSS_MODEL_UBLOX7, GNSS_MODEL_UBLOX8, GNSS_MODEL_UBLOX9, GNSS_MODEL_UBLOX10))
softsleepSupported = true;
#ifdef PIN_GPS_STANDBY // L76B, L76K and clones have a standby pin
softsleepSupported = true;
#endif
// How long does gps_update_interval need to be, for GPS_HARDSLEEP to become more efficient than GPS_SOFTSLEEP?
// Heuristic equation. A compromise manually fitted to power observations from U-blox NEO-6M and M10050
// https://www.desmos.com/calculator/6gvjghoumr
// This is not particularly accurate, but probably an impromevement over a single, fixed threshold
uint32_t hardsleepThreshold = (2750 * pow(predictedSearchDuration / 1000, 1.22));
LOG_DEBUG("gps_update_interval >= %us needed to justify hardsleep\n", hardsleepThreshold / 1000);
// If update interval too short: softsleep (if supported by hardware)
if (softsleepSupported && updateInterval < hardsleepThreshold)
setPowerState(GPS_SOFTSLEEP, sleepTime);
if (softsleepSupported) {
// How long does gps_update_interval need to be, for GPS_HARDSLEEP to become more efficient than GPS_SOFTSLEEP?
// Heuristic equation. A compromise manually fitted to power observations from U-blox NEO-6M and M10050
// https://www.desmos.com/calculator/6gvjghoumr
// This is not particularly accurate, but probably an impromevement over a single, fixed threshold
uint32_t hardsleepThreshold = (2750 * pow(predictedSearchDuration / 1000, 1.22));
LOG_DEBUG("gps_update_interval >= %us needed to justify hardsleep\n", hardsleepThreshold / 1000);
// If update interval too short: softsleep (if supported by hardware)
if (updateInterval < hardsleepThreshold) {
setPowerState(GPS_SOFTSLEEP, sleepTime);
return;
}
}
// If update interval long enough (or softsleep unsupported): hardsleep instead
else
setPowerState(GPS_HARDSLEEP, sleepTime);
setPowerState(GPS_HARDSLEEP, sleepTime);
}
}
@@ -1101,7 +988,9 @@ int32_t GPS::runOnce()
// if we have received valid NMEA claim we are connected
setConnected();
} else {
if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) && (gnssModel == GNSS_MODEL_UBLOX)) {
if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) &&
IS_ONE_OF(gnssModel, GNSS_MODEL_UBLOX6, GNSS_MODEL_UBLOX7, GNSS_MODEL_UBLOX8, GNSS_MODEL_UBLOX9,
GNSS_MODEL_UBLOX10)) {
// reset the GPS on next bootup
if (devicestate.did_gps_reset && scheduling.elapsedSearchMs() > 60 * 1000UL && !hasFlow()) {
LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n");
@@ -1195,18 +1084,19 @@ int GPS::prepareDeepSleep(void *unused)
GnssModel_t GPS::probe(int serialSpeed)
{
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL)
_serial_gps->end();
_serial_gps->begin(serialSpeed);
#elif defined(ARCH_RP2040)
_serial_gps->end();
_serial_gps->setFIFOSize(256);
_serial_gps->begin(serialSpeed);
#else
if (_serial_gps->baudRate() != serialSpeed) {
LOG_DEBUG("Setting Baud to %i\n", serialSpeed);
_serial_gps->updateBaudRate(serialSpeed);
}
#endif
#ifdef GNSS_AIROHA
return GNSS_MODEL_AG3335;
#endif
memset(&info, 0, sizeof(struct uBloxGnssModelInfo));
uint8_t buffer[768] = {0};
@@ -1225,7 +1115,12 @@ GnssModel_t GPS::probe(int serialSpeed)
PROBE_SIMPLE("ATGM332D", "$PCAS06,1*1A", "$GPTXT,01,01,02,HW=ATGM332D", GNSS_MODEL_ATGM336H, 500);
/* Airoha (Mediatek) AG3335A/M/S, A3352Q, Quectel L89 2.0, SimCom SIM65M */
PROBE_SIMPLE("AG3335", "PAIR020*38", "$PAIR020,AG3335", GNSS_MODEL_AG3335, 500);
_serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF to reduce volume
_serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF to reduce volume
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration
PROBE_SIMPLE("AG3335", "$PAIR021*39", "$PAIR021,AG3335", GNSS_MODEL_AG3335, 500);
PROBE_SIMPLE("AG3352", "$PAIR021*39", "$PAIR021,AG3352", GNSS_MODEL_AG3352, 500);
PROBE_SIMPLE("LC86", "$PQTMVERNO*58", "$PQTMVERNO,LC86", GNSS_MODEL_AG3352, 500);
PROBE_SIMPLE("L76K", "$PCAS06,0*1B", "$GPTXT,01,01,02,SW=", GNSS_MODEL_MTK, 500);
@@ -1260,9 +1155,13 @@ GnssModel_t GPS::probe(int serialSpeed)
_serial_gps->write(_message_prt, sizeof(_message_prt));
delay(500);
serialSpeed = 9600;
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL)
_serial_gps->end();
_serial_gps->begin(serialSpeed);
#elif defined(ARCH_RP2040)
_serial_gps->end();
_serial_gps->setFIFOSize(256);
_serial_gps->begin(serialSpeed);
#else
_serial_gps->updateBaudRate(serialSpeed);
#endif
@@ -1320,9 +1219,9 @@ GnssModel_t GPS::probe(int serialSpeed)
strncpy((char *)buffer, &(info.extension[i][4]), sizeof(buffer));
// LOG_DEBUG("GetModel:%s\n", (char *)buffer);
if (strlen((char *)buffer)) {
LOG_INFO("UBlox GNSS probe succeeded, using UBlox %s GNSS Module\n", (char *)buffer);
LOG_INFO("%s detected, using GNSS_MODEL_UBLOX\n", (char *)buffer);
} else {
LOG_INFO("UBlox GNSS probe succeeded, using UBlox GNSS Module\n");
LOG_INFO("Generic Ublox detected, using GNSS_MODEL_UBLOX\n");
}
} else if (!strncmp(info.extension[i], "PROTVER", 7)) {
char *ptr = nullptr;
@@ -1337,9 +1236,20 @@ GnssModel_t GPS::probe(int serialSpeed)
}
}
}
if (strncmp(info.hwVersion, "00040007", 8) == 0) {
return GNSS_MODEL_UBLOX6;
} else if (strncmp(info.hwVersion, "00070000", 8) == 0) {
return GNSS_MODEL_UBLOX7;
} else if (strncmp(info.hwVersion, "00080000", 8) == 0) {
return GNSS_MODEL_UBLOX8;
} else if (strncmp(info.hwVersion, "00190000", 8) == 0) {
return GNSS_MODEL_UBLOX9;
} else if (strncmp(info.hwVersion, "000A0000", 8) == 0) {
return GNSS_MODEL_UBLOX10;
}
}
return GNSS_MODEL_UBLOX;
return GNSS_MODEL_UNKNOWN;
}
GPS *GPS::createGps()
@@ -1423,6 +1333,9 @@ GPS *GPS::createGps()
LOG_DEBUG("Using GPIO%d for GPS RX\n", new_gps->rx_gpio);
LOG_DEBUG("Using GPIO%d for GPS TX\n", new_gps->tx_gpio);
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, new_gps->rx_gpio, new_gps->tx_gpio);
#elif defined(ARCH_RP2040)
_serial_gps->setFIFOSize(256);
_serial_gps->begin(GPS_BAUDRATE);
#else
_serial_gps->begin(GPS_BAUDRATE);
#endif
@@ -1510,16 +1423,15 @@ bool GPS::lookForTime()
#ifdef GNSS_AIROHA
uint8_t fix = reader.fixQuality();
uint32_t now = millis();
if (fix > 0) {
if (lastFixStartMsec > 0) {
if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) {
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
return false;
} else {
clearBuffer();
}
} else {
lastFixStartMsec = now;
lastFixStartMsec = millis();
return false;
}
} else {
@@ -1534,7 +1446,7 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
struct tm t;
t.tm_sec = ti.second();
t.tm_sec = ti.second() + round(ti.age() / 1000);
t.tm_min = ti.minute();
t.tm_hour = ti.hour();
t.tm_mday = d.day();
@@ -1542,8 +1454,8 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
t.tm_year = d.year() - 1900;
t.tm_isdst = false;
if (t.tm_mon > -1) {
LOG_DEBUG("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);
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d age %d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
t.tm_sec, ti.age());
perhapsSetRTC(RTCQualityGPS, t);
return true;
} else
@@ -1563,16 +1475,15 @@ bool GPS::lookForLocation()
#ifdef GNSS_AIROHA
if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) {
uint8_t fix = reader.fixQuality();
uint32_t now = millis();
if (fix > 0) {
if (lastFixStartMsec > 0) {
if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) {
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
return false;
} else {
clearBuffer();
}
} else {
lastFixStartMsec = now;
lastFixStartMsec = millis();
return false;
}
} else {

View File

@@ -26,11 +26,16 @@ struct uBloxGnssModelInfo {
typedef enum {
GNSS_MODEL_ATGM336H,
GNSS_MODEL_MTK,
GNSS_MODEL_UBLOX,
GNSS_MODEL_UBLOX6,
GNSS_MODEL_UBLOX7,
GNSS_MODEL_UBLOX8,
GNSS_MODEL_UBLOX9,
GNSS_MODEL_UBLOX10,
GNSS_MODEL_UC6580,
GNSS_MODEL_UNKNOWN,
GNSS_MODEL_MTK_L76B,
GNSS_MODEL_AG3335
GNSS_MODEL_AG3335,
GNSS_MODEL_AG3352
} GnssModel_t;
typedef enum {
@@ -101,7 +106,7 @@ class GPS : private concurrency::OSThread
public:
/** If !NULL we will use this serial port to construct our GPS */
#if defined(RPI_PICO_WAVESHARE)
#if defined(ARCH_RP2040)
static SerialUART *_serial_gps;
#else
static HardwareSerial *_serial_gps;
@@ -129,6 +134,7 @@ class GPS : private concurrency::OSThread
static const uint8_t _message_GGA[];
static const uint8_t _message_PMS[];
static const uint8_t _message_SAVE[];
static const uint8_t _message_SAVE_10[];
// VALSET Commands for M10
static const uint8_t _message_VALSET_PM[];
@@ -309,4 +315,4 @@ class GPS : private concurrency::OSThread
};
extern GPS *gps;
#endif // Exclude GPS
#endif // Exclude GPS

View File

@@ -75,10 +75,13 @@ uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const
uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos)
{
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
tm *t = gmtime((time_t *)&pos.timestamp);
time_t timestamp = pos.timestamp;
tm *t = gmtime(&timestamp);
if (getRTCQuality() > 0) { // use the device clock if we got time from somewhere. If not, use the GPS timestamp.
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
t = gmtime((time_t *)&rtc_sec);
timestamp = rtc_sec;
t = gmtime(&timestamp);
}
uint32_t len = snprintf(

View File

@@ -2,6 +2,7 @@
#include "configuration.h"
#include "detect/ScanI2C.h"
#include "main.h"
#include <Throttle.h>
#include <sys/time.h>
#include <time.h>
@@ -29,7 +30,7 @@ void readFromRTC()
if (rtc_found.address == RV3028_RTC) {
uint32_t now = millis();
Melopero_RV3028 rtc;
#ifdef I2C_SDA1
#if WIRE_INTERFACES_COUNT == 2
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C();
@@ -43,7 +44,10 @@ void readFromRTC()
t.tm_sec = rtc.getSecond();
tv.tv_sec = gm_mktime(&t);
tv.tv_usec = 0;
LOG_DEBUG("Read RTC time from RV3028 as %ld\n", tv.tv_sec);
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
LOG_DEBUG("Read RTC time from RV3028 getTime as %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, printableEpoch);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
if (currentQuality == RTCQualityNone) {
@@ -55,7 +59,7 @@ void readFromRTC()
uint32_t now = millis();
PCF8563_Class rtc;
#ifdef I2C_SDA1
#if WIRE_INTERFACES_COUNT == 2
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.begin();
@@ -71,7 +75,10 @@ void readFromRTC()
t.tm_sec = tc.second;
tv.tv_sec = gm_mktime(&t);
tv.tv_usec = 0;
LOG_DEBUG("Read RTC time from PCF8563 as %ld\n", tv.tv_sec);
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
LOG_DEBUG("Read RTC time from PCF8563 getDateTime as %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, printableEpoch);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
if (currentQuality == RTCQualityNone) {
@@ -81,7 +88,8 @@ void readFromRTC()
#else
if (!gettimeofday(&tv, NULL)) {
uint32_t now = millis();
LOG_DEBUG("Read RTC time as %ld\n", tv.tv_sec);
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
LOG_DEBUG("Read RTC time as %ld\n", printableEpoch);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
}
@@ -101,6 +109,13 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
{
static uint32_t lastSetMsec = 0;
uint32_t now = millis();
uint32_t printableEpoch = tv->tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
#ifdef BUILD_EPOCH
if (tv->tv_sec < BUILD_EPOCH) {
LOG_WARN("Ignoring time (%ld) before build epoch (%ld)!\n", printableEpoch, BUILD_EPOCH);
return false;
}
#endif
bool shouldSet;
if (forceUpdate) {
@@ -110,10 +125,13 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
} else if (q > currentQuality) {
shouldSet = true;
LOG_DEBUG("Upgrading time to quality %s\n", RtcName(q));
} else if (q >= RTCQualityNTP && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
// Every 12 hrs we will slam in a new GPS or Phone GPS / NTP time, to correct for local RTC clock drift
} else if (q == RTCQualityGPS) {
shouldSet = true;
LOG_DEBUG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec);
LOG_DEBUG("Reapplying GPS time: %ld secs\n", printableEpoch);
} else if (q == RTCQualityNTP && !Throttle::isWithinTimespanMs(lastSetMsec, (12 * 60 * 60 * 1000UL))) {
// Every 12 hrs we will slam in a new NTP or Phone GPS / NTP time, to correct for local RTC clock drift
shouldSet = true;
LOG_DEBUG("Reapplying external time to correct clock drift %ld secs\n", printableEpoch);
} else {
shouldSet = false;
LOG_DEBUG("Current RTC quality: %s. Ignoring time of RTC quality of %s\n", RtcName(currentQuality), RtcName(q));
@@ -133,29 +151,29 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
#ifdef RV3028_RTC
if (rtc_found.address == RV3028_RTC) {
Melopero_RV3028 rtc;
#ifdef I2C_SDA1
#if WIRE_INTERFACES_COUNT == 2
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C();
#endif
tm *t = gmtime(&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);
LOG_DEBUG("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);
LOG_DEBUG("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, printableEpoch);
}
#elif defined(PCF8563_RTC)
if (rtc_found.address == PCF8563_RTC) {
PCF8563_Class rtc;
#ifdef I2C_SDA1
#if WIRE_INTERFACES_COUNT == 2
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.begin();
#endif
tm *t = gmtime(&tv->tv_sec);
rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)\n", t->tm_year + 1900, t->tm_mon + 1,
t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
}
#elif defined(ARCH_ESP32)
settimeofday(tv, NULL);
@@ -272,4 +290,4 @@ time_t gm_mktime(struct tm *tm)
#else
return mktime(tm);
#endif
}
}

View File

@@ -1,3 +1,10 @@
#define SEND_UBX_PACKET(TYPE, ID, DATA, ERRMSG, TIMEOUT) \
msglen = makeUBXPacket(TYPE, ID, sizeof(DATA), DATA); \
_serial_gps->write(UBXscratch, msglen); \
if (getACK(TYPE, ID, TIMEOUT) != GNSS_RESPONSE_OK) { \
LOG_WARN(#ERRMSG); \
}
// Power Management
uint8_t GPS::_message_PMREQ[] PROGMEM = {
@@ -316,6 +323,13 @@ const uint8_t GPS::_message_SAVE[] = {
0x17 // deviceMask: BBR, Flash, EEPROM, and SPI Flash
};
const uint8_t GPS::_message_SAVE_10[] = {
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x01 // deviceMask: only save to BBR
};
// As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR.
// BBR will survive a restart, and power off for a while, but modules with small backup
// batteries or super caps will not retain the config for a long power off time.
@@ -335,36 +349,36 @@ const uint8_t GPS::_message_SAVE[] = {
// has details on low-power modes
/*
CFG-PM2 has been replaced by many CFG-PM commands
CFG-PMS has been removed
CFG-PM-OPERATEMODE E1 (0 | 1 | 2) -> 1 (PSMOO), because sporadic position updates are required instead of continous tracking <10s
(PSMCT) CFG-PM-POSUPDATEPERIOD U4 -> 0ms, no self-timed wakup because receiver power mode is controlled via "software standby
mode" by legacy UBX-RXM-PMREQ request CFG-PM-ACQPERIOD U4 -> 0ms, because receiver power mode is controlled via "software standby
mode" by legacy UBX-RXM-PMREQ request CFG-PM-ONTIME U4 -> 0ms, optional I guess CFG-PM-EXTINTBACKUP L -> 1, force receiver into
BACKUP mode when EXTINT (should be connected to GPS_EN_PIN) pin is "low"
This is required because the receiver never enters low power mode if microcontroller is in deep-sleep.
Maybe the changing UART_RX levels trigger a wakeup but even with UBX-RXM-PMREQ[12] = 0x00 (all external wakeup sources disabled)
the receivcer remains in aquisition state -> potentially a bug
Workaround: Control the EXTINT pin by the GPS_EN_PIN signal
As mentioned in the M10 operational issues down below, power save won't allow the use of BDS B1C.
CFG-SIGNAL-BDS_B1C_ENA L -> 0
OPERATEMODE E1 2 (0 | 1 | 2)
POSUPDATEPERIOD U4 5
ACQPERIOD U4 10
GRIDOFFSET U4 0
ONTIME U2 1
MINACQTIME U1 0
MAXACQTIME U1 0
DONOTENTEROFF L 1
WAITTIMEFIX L 1
UPDATEEPH L 1
EXTINTWAKE L 0 no ext ints
EXTINTBACKUP L 0 no ext ints
EXTINTINACTIVE L 0 no ext ints
EXTINTACTIVITY U4 0 no ext ints
LIMITPEAKCURRENT L 1
// Ram layer config message:
// 01 01 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01
// b5 62 06 8a 26 00 00 01 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0
// 10 01 8b de
// BBR layer config message:
// 01 02 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01
// b5 62 06 8a 26 00 00 02 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0
// 10 01 8c 03
*/
const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x01, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01,
0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01};
const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x01, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01,
0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01};
const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
/*
CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR

View File

@@ -1,3 +1,4 @@
#include "Throttle.h"
#include "configuration.h"
#if defined(USE_EINK) && defined(USE_EINK_DYNAMICDISPLAY)
@@ -231,15 +232,13 @@ void EInkDynamicDisplay::checkForPromotion()
// Is it too soon for another frame of this type?
void EInkDynamicDisplay::checkRateLimiting()
{
uint32_t now = millis();
// Sanity check: millis() overflow - just let the update run..
if (previousRunMs > now)
if (previousRunMs > millis())
return;
// Skip update: too soon for BACKGROUND
if (frameFlags == BACKGROUND) {
if (now - previousRunMs < EINK_LIMIT_RATE_BACKGROUND_SEC * 1000) {
if (Throttle::isWithinTimespanMs(previousRunMs, EINK_LIMIT_RATE_BACKGROUND_SEC * 1000)) {
refresh = SKIPPED;
reason = EXCEEDED_RATELIMIT_FULL;
return;
@@ -252,7 +251,7 @@ void EInkDynamicDisplay::checkRateLimiting()
// Skip update: too soon for RESPONSIVE
if (frameFlags & RESPONSIVE) {
if (now - previousRunMs < EINK_LIMIT_RATE_RESPONSIVE_SEC * 1000) {
if (Throttle::isWithinTimespanMs(previousRunMs, EINK_LIMIT_RATE_RESPONSIVE_SEC * 1000)) {
refresh = SKIPPED;
reason = EXCEEDED_RATELIMIT_FAST;
LOG_DEBUG("refresh=SKIPPED, reason=EXCEEDED_RATELIMIT_FAST, frameFlags=0x%x\n", frameFlags);

View File

@@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "Screen.h"
#include "../userPrefs.h"
#include "PowerMon.h"
#include "Throttle.h"
#include "configuration.h"
#if HAS_SCREEN
#include <OLEDDisplay.h>
@@ -47,6 +48,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "modules/AdminModule.h"
#include "modules/ExternalNotificationModule.h"
#include "modules/TextMessageModule.h"
#include "modules/WaypointModule.h"
#include "sleep.h"
#include "target_specific.h"
@@ -56,10 +58,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef ARCH_ESP32
#include "esp_task_wdt.h"
#include "modules/esp32/StoreForwardModule.h"
#include "modules/StoreForwardModule.h"
#endif
#if ARCH_PORTDUINO
#include "modules/StoreForwardModule.h"
#include "platform/portduino/PortduinoGlue.h"
#endif
@@ -117,6 +120,7 @@ static bool heartbeat = false;
#define SCREEN_HEIGHT display->getHeight()
#include "graphics/ScreenFonts.h"
#include <Throttle.h>
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
@@ -1004,55 +1008,55 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
display->setColor(WHITE);
#ifndef EXCLUDE_EMOJI
if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"\U0001F44D") == 0) {
if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F44D") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height,
thumbup);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"\U0001F44E") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F44E") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height,
thumbdown);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - question_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - question_height) / 2 + 2 + 5, question_width, question_height,
question);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"‼️") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "‼️") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - bang_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - bang_height) / 2 + 2 + 5,
bang_width, bang_height, bang);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"\U0001F4A9") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F4A9") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - poo_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - poo_height) / 2 + 2 + 5,
poo_width, poo_height, poo);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\xf0\x9f\xa4\xa3") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - haha_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - haha_height) / 2 + 2 + 5,
haha_width, haha_height, haha);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"\U0001F44B") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F44B") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - wave_icon_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - wave_icon_height) / 2 + 2 + 5, wave_icon_width,
wave_icon_height, wave_icon);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"\U0001F920") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F920") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - cowboy_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - cowboy_height) / 2 + 2 + 5, cowboy_width, cowboy_height,
cowboy);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"\U0001F42D") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F42D") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - deadmau5_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - deadmau5_height) / 2 + 2 + 5, deadmau5_width, deadmau5_height,
deadmau5);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"\xE2\x98\x80\xEF\xB8\x8F") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\xE2\x98\x80\xEF\xB8\x8F") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - sun_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - sun_height) / 2 + 2 + 5,
sun_width, sun_height, sun);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"\u2614") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\u2614") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - rain_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - rain_height) / 2 + 2 + 10,
rain_width, rain_height, rain);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"☁️") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "☁️") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - cloud_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - cloud_height) / 2 + 2 + 5, cloud_width, cloud_height, cloud);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"🌫️") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "🌫️") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - fog_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - fog_height) / 2 + 2 + 5,
fog_width, fog_height, fog);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"\xf0\x9f\x98\x88") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\xf0\x9f\x98\x88") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - devil_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - devil_height) / 2 + 2 + 5, devil_width, devil_height, devil);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), u8"♥️") == 0) {
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "♥️") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - heart_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - heart_height) / 2 + 2 + 5, heart_width, heart_height, heart);
} else {
@@ -1093,8 +1097,8 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const NodeStat
{
char usersString[20];
snprintf(usersString, sizeof(usersString), "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(USE_ST7789) || \
defined(HX8357_CS)) && \
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || \
defined(USE_ST7789) || defined(HX8357_CS)) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
display->drawFastImage(x, y + 3, 8, 8, imgUser);
#else
@@ -1285,8 +1289,8 @@ static int8_t prevFrame = -1;
// Draw the arrow pointing to a node's location
void Screen::drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, uint16_t compassDiam, float headingRadian)
{
Point tip(0.0f, 0.5f), tail(0.0f, -0.5f); // pointing up initially
float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f;
Point tip(0.0f, 0.5f), tail(0.0f, -0.35f); // pointing up initially
float arrowOffsetX = 0.14f, arrowOffsetY = 1.0f;
Point leftArrow(tip.x - arrowOffsetX, tip.y - arrowOffsetY), rightArrow(tip.x + arrowOffsetX, tip.y - arrowOffsetY);
Point *arrowPoints[] = {&tip, &tail, &leftArrow, &rightArrow};
@@ -1296,9 +1300,19 @@ void Screen::drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t com
arrowPoints[i]->scale(compassDiam * 0.6);
arrowPoints[i]->translate(compassX, compassY);
}
/* Old arrow
display->drawLine(tip.x, tip.y, tail.x, tail.y);
display->drawLine(leftArrow.x, leftArrow.y, tip.x, tip.y);
display->drawLine(rightArrow.x, rightArrow.y, tip.x, tip.y);
display->drawLine(leftArrow.x, leftArrow.y, tail.x, tail.y);
display->drawLine(rightArrow.x, rightArrow.y, tail.x, tail.y);
*/
#ifdef USE_EINK
display->drawTriangle(tip.x, tip.y, rightArrow.x, rightArrow.y, tail.x, tail.y);
#else
display->fillTriangle(tip.x, tip.y, rightArrow.x, rightArrow.y, tail.x, tail.y);
#endif
display->drawTriangle(tip.x, tip.y, leftArrow.x, leftArrow.y, tail.x, tail.y);
}
// Get a string representation of the time passed since something happened
@@ -1336,22 +1350,27 @@ void Screen::drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t co
// If north is supposed to be at the top of the compass we want rotation to be +0
if (config.display.compass_north_top)
myHeading = -0;
Point N1(-0.04f, 0.65f), N2(0.04f, 0.65f);
/* N sign points currently not deleted*/
Point N1(-0.04f, 0.65f), N2(0.04f, 0.65f); // N sign points (N1-N4)
Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f);
Point *rosePoints[] = {&N1, &N2, &N3, &N4};
Point NC1(0.00f, 0.50f); // north circle center point
Point *rosePoints[] = {&N1, &N2, &N3, &N4, &NC1};
uint16_t compassDiam = Screen::getCompassDiam(SCREEN_WIDTH, SCREEN_HEIGHT);
for (int i = 0; i < 4; i++) {
for (int i = 0; i < 5; i++) {
// North on compass will be negative of heading
rosePoints[i]->rotate(-myHeading);
rosePoints[i]->scale(compassDiam);
rosePoints[i]->translate(compassX, compassY);
}
/* changed the N sign to a small circle on the compass circle.
display->drawLine(N1.x, N1.y, N3.x, N3.y);
display->drawLine(N2.x, N2.y, N4.x, N4.y);
display->drawLine(N1.x, N1.y, N4.x, N4.y);
*/
display->drawCircle(NC1.x, NC1.y, 4); // North sign circle, 4px radius is sufficient for all displays.
}
uint16_t Screen::getCompassDiam(uint32_t displayWidth, uint32_t displayHeight)
@@ -1515,7 +1534,8 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
#elif defined(USE_SSD1306)
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014) || defined(HX8357_CS)
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7789_CS) || defined(RAK14014) || \
defined(HX8357_CS)
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
#elif defined(USE_EINK) && !defined(USE_EINK_DYNAMICDISPLAY)
@@ -1654,6 +1674,11 @@ void Screen::setup()
static_cast<SH1106Wire *>(dispdev)->setSubtype(7);
#endif
#if defined(USE_ST7789) && defined(TFT_MESH)
// Heltec T114 and T190: honor a custom text color, if defined in variant.h
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
#endif
// Initialising the UI will init the display too.
ui->init();
@@ -1707,8 +1732,11 @@ void Screen::setup()
// Standard behaviour is to FLIP the screen (needed on T-Beam). If this config item is set, unflip it, and thereby logically
// flip it. If you have a headache now, you're welcome.
if (!config.display.flip_screen) {
#if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014) || defined(HX8357_CS)
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7789_CS) || \
defined(RAK14014) || defined(HX8357_CS)
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
#elif defined(USE_ST7789)
static_cast<ST7789Spi *>(dispdev)->flipScreenVertically();
#else
dispdev->flipScreenVertically();
#endif
@@ -1856,13 +1884,7 @@ int32_t Screen::runOnce()
handleSetOn(false);
break;
case Cmd::ON_PRESS:
// If a nag notification is running, stop it
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
externalNotificationModule->stopNow();
} else {
// Don't advance the screen if we just wanted to switch off the nag notification
handleOnPress();
}
handleOnPress();
break;
case Cmd::SHOW_PREV_FRAME:
handleShowPrevFrame();
@@ -1925,7 +1947,7 @@ int32_t Screen::runOnce()
if (showingNormalScreen) {
// standard screen loop handling here
if (config.display.auto_screen_carousel_secs > 0 &&
(millis() - lastScreenTransition) > (config.display.auto_screen_carousel_secs * 1000)) {
!Throttle::isWithinTimespanMs(lastScreenTransition, config.display.auto_screen_carousel_secs * 1000)) {
// If an E-Ink display struggles with fast refresh, force carousel to use full refresh instead
// Carousel is potentially a major source of E-Ink display wear
@@ -2086,8 +2108,13 @@ void Screen::setFrames(FrameFocus focus)
// Check if the module being drawn has requested focus
// We will honor this request later, if setFrames was triggered by a UIFrameEvent
MeshModule *m = *i;
if (m->isRequestingFocus())
if (m->isRequestingFocus()) {
fsi.positions.focusedModule = numframes;
}
// Identify the position of specific modules, if we need to know this later
if (m == waypointModule)
fsi.positions.waypoint = numframes;
numframes++;
}
@@ -2106,8 +2133,8 @@ void Screen::setFrames(FrameFocus focus)
#endif
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
fsi.positions.textMessage = numframes;
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
fsi.positions.textMessage = numframes;
normalFrames[numframes++] = drawTextMessageFrame;
}
@@ -2169,7 +2196,7 @@ void Screen::setFrames(FrameFocus focus)
case FOCUS_PRESERVE:
// If we can identify which type of frame "originalPosition" was, can move directly to it in the new frameset
FramesetInfo &oldFsi = this->framesetInfo;
const FramesetInfo &oldFsi = this->framesetInfo;
if (originalPosition == oldFsi.positions.log)
ui->switchToFrame(fsi.positions.log);
else if (originalPosition == oldFsi.positions.settings)
@@ -2209,6 +2236,31 @@ void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
setFastFramerate();
}
// Dismisses the currently displayed screen frame, if possible
// Relevant for text message, waypoint, others in future?
// Triggered with a CardKB keycombo
void Screen::dismissCurrentFrame()
{
uint8_t currentFrame = ui->getUiState()->currentFrame;
bool dismissed = false;
if (currentFrame == framesetInfo.positions.textMessage && devicestate.has_rx_text_message) {
LOG_INFO("Dismissing Text Message\n");
devicestate.has_rx_text_message = false;
dismissed = true;
}
else if (currentFrame == framesetInfo.positions.waypoint && devicestate.has_rx_waypoint) {
LOG_DEBUG("Dismissing Waypoint\n");
devicestate.has_rx_waypoint = false;
dismissed = true;
}
// If we did make changes to dismiss, we now need to regenerate the frameset
if (dismissed)
setFrames();
}
void Screen::handleStartFirmwareUpdateScreen()
{
LOG_DEBUG("showing firmware screen\n");
@@ -2418,10 +2470,10 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
if (moduleConfig.store_forward.enabled) {
#ifdef ARCH_ESP32
if (millis() - storeForwardModule->lastHeartbeat >
(storeForwardModule->heartbeatInterval * 1200)) { // no heartbeat, overlap a bit
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(USE_ST7789) || \
defined(HX8357_CS)) && \
if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat,
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || \
defined(USE_ST7789) || defined(HX8357_CS)) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
imgQuestionL1);
@@ -2432,8 +2484,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
imgQuestion);
#endif
} else {
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(USE_ST7789) || \
defined(HX8357_CS)) && \
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || \
defined(USE_ST7789) || defined(HX8357_CS)) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8,
imgSFL1);
@@ -2447,8 +2499,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
#endif
} else {
// TODO: Raspberry Pi supports more than just the one screen size
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(USE_ST7789) || \
defined(HX8357_CS) || ARCH_PORTDUINO) && \
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || \
defined(USE_ST7789) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
imgInfoL1);
@@ -2721,12 +2773,23 @@ int Screen::handleInputEvent(const InputEvent *event)
}
#endif
if (showingNormalScreen && moduleFrames.size() == 0) {
// LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
showPrevFrame();
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
showNextFrame();
// Use left or right input from a keyboard to move between frames,
// so long as a mesh module isn't using these events for some other purpose
if (showingNormalScreen) {
// Ask any MeshModules if they're handling keyboard input right now
bool inputIntercepted = false;
for (MeshModule *module : moduleFrames) {
if (module->interceptingKeyboardInput())
inputIntercepted = true;
}
// If no modules are using the input, move between frames
if (!inputIntercepted) {
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT))
showPrevFrame();
else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))
showNextFrame();
}
}

View File

@@ -454,6 +454,9 @@ class Screen : public concurrency::OSThread
void setWelcomeFrames();
// Dismiss the currently focussed frame, if possible (e.g. text message, waypoint)
void dismissCurrentFrame();
#ifdef USE_EINK
/// Draw an image to remain on E-Ink display after screen off
void setScreensaverFrames(FrameCallback einkScreensaver = NULL);
@@ -503,11 +506,14 @@ class Screen : public concurrency::OSThread
void handleStartFirmwareUpdateScreen();
// Info collected by setFrames method.
// Index location of specific frames. Used to apply the FrameFocus parameter of setFrames
// Index location of specific frames.
// - Used to apply the FrameFocus parameter of setFrames
// - Used to dismiss the currently shown frame (txt; waypoint) by CardKB combo
struct FramesetInfo {
struct FramePositions {
uint8_t fault = 0;
uint8_t textMessage = 0;
uint8_t waypoint = 0;
uint8_t focusedModule = 0;
uint8_t log = 0;
uint8_t settings = 0;

View File

@@ -12,8 +12,8 @@
#include "graphics/fonts/OLEDDisplayFontsUA.h"
#endif
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(USE_ST7789) || \
defined(HX8357_CS)) && \
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || \
defined(USE_ST7789) || defined(HX8357_CS)) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
// The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16 // Height: 19

View File

@@ -500,10 +500,126 @@ class LGFX : public lgfx::LGFX_Device
static LGFX *tft = nullptr;
#elif defined(ST7701_CS)
#include <LovyanGFX.hpp> // Graphics and font library for ST7701 driver chip
#include <lgfx/v1/platforms/esp32s3/Bus_RGB.hpp>
#include <lgfx/v1/platforms/esp32s3/Panel_RGB.hpp>
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ST7701 _panel_instance;
lgfx::Bus_RGB _bus_instance;
lgfx::Light_PWM _light_instance;
lgfx::Touch_FT5x06 _touch_instance;
public:
LGFX(void)
{
{
auto cfg = _panel_instance.config();
cfg.memory_width = 800;
cfg.memory_height = 480;
cfg.panel_width = TFT_WIDTH;
cfg.panel_height = TFT_HEIGHT;
cfg.offset_x = TFT_OFFSET_X;
cfg.offset_y = TFT_OFFSET_Y;
_panel_instance.config(cfg);
}
{
auto cfg = _panel_instance.config_detail();
cfg.pin_cs = ST7701_CS;
cfg.pin_sclk = ST7701_SCK;
cfg.pin_mosi = ST7701_SDA;
// cfg.use_psram = 1;
_panel_instance.config_detail(cfg);
}
{
auto cfg = _bus_instance.config();
cfg.panel = &_panel_instance;
#ifdef SENSECAP_INDICATOR
cfg.pin_d0 = GPIO_NUM_15; // B0
cfg.pin_d1 = GPIO_NUM_14; // B1
cfg.pin_d2 = GPIO_NUM_13; // B2
cfg.pin_d3 = GPIO_NUM_12; // B3
cfg.pin_d4 = GPIO_NUM_11; // B4
cfg.pin_d5 = GPIO_NUM_10; // G0
cfg.pin_d6 = GPIO_NUM_9; // G1
cfg.pin_d7 = GPIO_NUM_8; // G2
cfg.pin_d8 = GPIO_NUM_7; // G3
cfg.pin_d9 = GPIO_NUM_6; // G4
cfg.pin_d10 = GPIO_NUM_5; // G5
cfg.pin_d11 = GPIO_NUM_4; // R0
cfg.pin_d12 = GPIO_NUM_3; // R1
cfg.pin_d13 = GPIO_NUM_2; // R2
cfg.pin_d14 = GPIO_NUM_1; // R3
cfg.pin_d15 = GPIO_NUM_0; // R4
cfg.pin_henable = GPIO_NUM_18;
cfg.pin_vsync = GPIO_NUM_17;
cfg.pin_hsync = GPIO_NUM_16;
cfg.pin_pclk = GPIO_NUM_21;
cfg.freq_write = 12000000;
cfg.hsync_polarity = 0;
cfg.hsync_front_porch = 10;
cfg.hsync_pulse_width = 8;
cfg.hsync_back_porch = 50;
cfg.vsync_polarity = 0;
cfg.vsync_front_porch = 10;
cfg.vsync_pulse_width = 8;
cfg.vsync_back_porch = 20;
cfg.pclk_active_neg = 0;
cfg.de_idle_high = 1;
cfg.pclk_idle_high = 0;
#endif
_bus_instance.config(cfg);
}
_panel_instance.setBus(&_bus_instance);
{
auto cfg = _light_instance.config();
cfg.pin_bl = ST7701_BL;
_light_instance.config(cfg);
}
_panel_instance.light(&_light_instance);
{
auto cfg = _touch_instance.config();
cfg.pin_cs = -1;
cfg.x_min = 0;
cfg.x_max = 479;
cfg.y_min = 0;
cfg.y_max = 479;
cfg.pin_int = -1; // don't use SCREEN_TOUCH_INT;
cfg.pin_rst = SCREEN_TOUCH_RST;
cfg.bus_shared = true;
cfg.offset_rotation = TFT_OFFSET_ROTATION;
cfg.i2c_port = TOUCH_I2C_PORT;
cfg.i2c_addr = TOUCH_SLAVE_ADDRESS;
cfg.pin_sda = I2C_SDA;
cfg.pin_scl = I2C_SCL;
cfg.freq = 400000;
_touch_instance.config(cfg);
_panel_instance.setTouch(&_touch_instance);
}
setPanel(&_panel_instance);
}
};
static LGFX *tft = nullptr;
#endif
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014) || defined(HX8357_CS) || \
(ARCH_PORTDUINO && HAS_SCREEN != 0)
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014) || \
defined(HX8357_CS) || (ARCH_PORTDUINO && HAS_SCREEN != 0)
#include "SPILock.h"
#include "TFTDisplay.h"
#include <SPI.h>
@@ -709,7 +825,6 @@ bool TFTDisplay::connect()
#ifdef UNPHONE
unphone.backlight(true); // using unPhone library
LOG_INFO("Power to TFT Backlight\n");
#endif
tft->init();
@@ -725,7 +840,7 @@ bool TFTDisplay::connect()
attachInterrupt(digitalPinToInterrupt(SCREEN_TOUCH_INT), rak14014_tpIntHandle, FALLING);
#elif defined(T_DECK) || defined(PICOMPUTER_S3) || defined(CHATTER_2)
tft->setRotation(1); // T-Deck has the TFT in landscape
#elif defined(T_WATCH_S3)
#elif defined(T_WATCH_S3) || defined(SENSECAP_INDICATOR)
tft->setRotation(2); // T-Watch S3 left-handed orientation
#else
tft->setRotation(3); // Orient horizontal and wide underneath the silkscreen name label

View File

@@ -20,8 +20,8 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03
0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
#endif
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(USE_ST7789) || \
defined(HX8357_CS) || ARCH_PORTDUINO) && \
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || \
defined(USE_ST7789) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};

View File

@@ -1,5 +1,5 @@
#include "ExpressLRSFiveWay.h"
#include "Throttle.h"
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
@@ -76,11 +76,10 @@ void ExpressLRSFiveWay::update(int *keyValue, bool *keyLongPressed)
*keyValue = NO_PRESS;
int newKey = readKey();
uint32_t now = millis();
if (keyInProcess == NO_PRESS) {
// New key down
if (newKey != NO_PRESS) {
keyDownStart = now;
keyDownStart = millis();
// DBGLN("down=%u", newKey);
}
} else {
@@ -88,7 +87,7 @@ void ExpressLRSFiveWay::update(int *keyValue, bool *keyLongPressed)
if (newKey == NO_PRESS) {
// DBGLN("up=%u", keyInProcess);
if (!isLongPressed) {
if ((now - keyDownStart) > KEY_DEBOUNCE_MS) {
if (!Throttle::isWithinTimespanMs(keyDownStart, KEY_DEBOUNCE_MS)) {
*keyValue = keyInProcess;
*keyLongPressed = false;
}
@@ -101,7 +100,7 @@ void ExpressLRSFiveWay::update(int *keyValue, bool *keyLongPressed)
}
// else still pressing, waiting for long if not already signaled
else if (!isLongPressed) {
if ((now - keyDownStart) > KEY_LONG_PRESS_MS) {
if (!Throttle::isWithinTimespanMs(keyDownStart, KEY_LONG_PRESS_MS)) {
*keyValue = keyInProcess;
*keyLongPressed = true;
isLongPressed = true;

View File

@@ -11,6 +11,7 @@
#define INPUT_BROKER_MSG_GPS_TOGGLE 0x9e
#define INPUT_BROKER_MSG_MUTE_TOGGLE 0xac
#define INPUT_BROKER_MSG_SEND_PING 0xaf
#define INPUT_BROKER_MSG_DISMISS_FRAME 0x8b
#define INPUT_BROKER_MSG_LEFT 0xb4
#define INPUT_BROKER_MSG_UP 0xb5
#define INPUT_BROKER_MSG_DOWN 0xb6

View File

@@ -6,6 +6,7 @@
#include "ScanAndSelect.h"
#include "modules/CannedMessageModule.h"
#include <Throttle.h>
// Config
static const char name[] = "scanAndSelect"; // should match "allow input source" string
@@ -75,7 +76,7 @@ int32_t ScanAndSelectInput::runOnce()
else {
// Duration enough for long press
// Long press not yet fired (prevent repeat firing while held)
if (!longPressFired && now - downSinceMs > durationLongMs) {
if (!longPressFired && Throttle::isWithinTimespanMs(downSinceMs, durationLongMs)) {
longPressFired = true;
longPress();
}
@@ -91,7 +92,7 @@ int32_t ScanAndSelectInput::runOnce()
// Long press event didn't already fire
if (held && !longPressFired) {
// Duration enough for short press
if (now - downSinceMs > durationShortMs) {
if (!Throttle::isWithinTimespanMs(downSinceMs, durationShortMs)) {
shortPress();
}
}

View File

@@ -1,5 +1,6 @@
#include "SerialKeyboard.h"
#include "configuration.h"
#include <Throttle.h>
#ifdef INPUTBROKER_SERIAL_TYPE
#define CANNED_MESSAGE_MODULE_ENABLE 1 // in case it's not set in the variant file
@@ -73,7 +74,7 @@ int32_t SerialKeyboard::runOnce()
// Serial.print ("X");
// Serial.println (shiftRegister2, BIN);
if (millis() - lastPressTime > 500) {
if (!Throttle::isWithinTimespanMs(lastPressTime, 500)) {
quickPress = 0;
}

View File

@@ -9,14 +9,14 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
void CardKbI2cImpl::init()
{
#ifndef ARCH_PORTDUINO
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO)
if (cardkb_found.address == 0x00) {
LOG_DEBUG("Rescanning for I2C keyboard\n");
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR};
uint8_t i2caddr_asize = 3;
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
#if defined(I2C_SDA1)
#if WIRE_INTERFACES_COUNT == 2
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize);
#endif
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize);
@@ -57,4 +57,4 @@ void CardKbI2cImpl::init()
}
#endif
inputBroker->registerSource(this);
}
}

View File

@@ -33,7 +33,7 @@ int32_t KbI2cBase::runOnce()
if (!i2cBus) {
switch (cardkb_found.port) {
case ScanI2C::WIRE1:
#ifdef I2C_SDA1
#if WIRE_INTERFACES_COUNT == 2
LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
i2cBus = &Wire1;
if (cardkb_found.address == BBQ10_KB_ADDR) {
@@ -296,6 +296,7 @@ int32_t KbI2cBase::runOnce()
case 0xac: // fn+m INPUT_BROKER_MSG_MUTE_TOGGLE
case 0x9e: // fn+g INPUT_BROKER_MSG_GPS_TOGGLE
case 0xaf: // fn+space INPUT_BROKER_MSG_SEND_PING
case 0x8b: // fn+del INPUT_BROKEN_MSG_DISMISS_FRAME
// just pass those unmodified
e.inputEvent = ANYKEY;
e.kbchar = c;

View File

@@ -11,16 +11,16 @@
#include "airtime.h"
#include "buzz.h"
#include "error.h"
#include "power.h"
// #include "debug.h"
#include "FSCommon.h"
#include "Led.h"
#include "RTC.h"
#include "SPILock.h"
#include "Throttle.h"
#include "concurrency/OSThread.h"
#include "concurrency/Periodic.h"
#include "detect/ScanI2C.h"
#include "error.h"
#include "power.h"
#if !MESHTASTIC_EXCLUDE_I2C
#include "detect/ScanI2CTwoWire.h"
@@ -32,13 +32,13 @@
#include "graphics/Screen.h"
#include "main.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include "meshUtils.h"
#include "modules/Modules.h"
#include "shutdown.h"
#include "sleep.h"
#include "target_specific.h"
#include <memory>
#include <utility>
// #include <driver/rtc_io.h>
#ifdef ARCH_ESP32
#if !MESHTASTIC_EXCLUDE_WEBSERVER
@@ -72,6 +72,7 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
#include "LLCC68Interface.h"
#include "LR1110Interface.h"
#include "LR1120Interface.h"
#include "LR1121Interface.h"
#include "RF95Interface.h"
#include "SX1262Interface.h"
#include "SX1268Interface.h"
@@ -102,8 +103,8 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
#include "AmbientLightingThread.h"
#include "PowerFSMThread.h"
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
#include "AccelerometerThread.h"
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C
#include "motion/AccelerometerThread.h"
AccelerometerThread *accelerometerThread = nullptr;
#endif
@@ -322,15 +323,19 @@ void setup()
#ifdef BUTTON_PIN
#ifdef ARCH_ESP32
// If the button is connected to GPIO 12, don't enable the ability to use
// meshtasticAdmin on the device.
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT);
#if ESP_ARDUINO_VERSION_MAJOR >= 3
#ifdef BUTTON_NEED_PULLUP
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP);
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#endif
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
delay(10);
#endif
#endif
#endif
#endif
@@ -360,6 +365,8 @@ void setup()
Wire1.begin();
#elif defined(I2C_SDA1) && !defined(ARCH_RP2040)
Wire1.begin(I2C_SDA1, I2C_SCL1);
#elif WIRE_INTERFACES_COUNT == 2
Wire1.begin();
#endif
#if defined(I2C_SDA) && defined(ARCH_RP2040)
@@ -390,7 +397,7 @@ void setup()
#endif
#ifdef AQ_SET_PIN
// RAK-12039 set pin for Air quality sensor
// RAK-12039 set pin for Air quality sensor. Detectable on I2C after ~3 seconds, so we need to rescan later
pinMode(AQ_SET_PIN, OUTPUT);
digitalWrite(AQ_SET_PIN, HIGH);
#endif
@@ -427,6 +434,8 @@ void setup()
#elif defined(I2C_SDA1) && !defined(ARCH_RP2040)
Wire1.begin(I2C_SDA1, I2C_SCL1);
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
#elif defined(NRF52840_XXAA) && (WIRE_INTERFACES_COUNT == 2)
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
#endif
#if defined(I2C_SDA) && defined(ARCH_RP2040)
@@ -552,6 +561,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31)
@@ -560,6 +570,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::HMC5883L, meshtastic_TelemetrySensorType_QMC5883L)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::VEML7700, meshtastic_TelemetrySensorType_VEML7700)
@@ -569,6 +580,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948)
i2cScanner.reset();
#endif
@@ -586,6 +598,9 @@ void setup()
// Hello
printInfo();
#ifdef BUILD_EPOCH
LOG_INFO("Build timestamp: %ld\n", BUILD_EPOCH);
#endif
#ifdef ARCH_ESP32
esp32Setup();
@@ -617,7 +632,13 @@ void setup()
buttonThread = new ButtonThread();
#endif
playStartMelody();
// only play start melody when role is not tracker or sensor
if (config.power.is_power_saving == true &&
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TRACKER,
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER, meshtastic_Config_DeviceConfig_Role_SENSOR))
LOG_DEBUG("Tracker/Sensor: Skipping start melody\n");
else
playStartMelody();
// fixed screen override?
if (config.display.oled != meshtastic_Config_DisplayConfig_OledType_OLED_AUTO)
@@ -633,7 +654,7 @@ void setup()
#endif
#if !MESHTASTIC_EXCLUDE_I2C
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
if (acc_info.type != ScanI2C::DeviceType::NONE) {
accelerometerThread = new AccelerometerThread(acc_info.type);
}
@@ -745,8 +766,8 @@ void setup()
#if !MESHTASTIC_EXCLUDE_I2C
// Don't call screen setup until after nodedb is setup (because we need
// the current region name)
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || \
defined(USE_ST7789)
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || \
defined(HX8357_CS) || defined(USE_ST7789)
screen->setup();
#elif defined(ARCH_PORTDUINO)
if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) {
@@ -760,12 +781,6 @@ void setup()
screen->print("Started...\n");
#ifdef SX126X_ANT_SW
// make analog PA vs not PA switch on SX126x eval board work properly
pinMode(SX126X_ANT_SW, OUTPUT);
digitalWrite(SX126X_ANT_SW, 1);
#endif
#ifdef PIN_PWR_DELAY_MS
// This may be required to give the peripherals time to power up.
delay(PIN_PWR_DELAY_MS);
@@ -870,8 +885,8 @@ void setup()
}
#endif
#if defined(RF95_IRQ)
if (!rIf) {
#if defined(RF95_IRQ) && RADIOLIB_EXCLUDE_SX127X != 1
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
rIf = new RF95Interface(RadioLibHAL, LORA_CS, RF95_IRQ, RF95_RESET, RF95_DIO1);
if (!rIf->init()) {
LOG_WARN("Failed to find RF95 radio\n");
@@ -884,8 +899,8 @@ void setup()
}
#endif
#if defined(USE_SX1262) && !defined(ARCH_PORTDUINO) && !defined(TCXO_OPTIONAL)
if (!rIf) {
#if defined(USE_SX1262) && !defined(ARCH_PORTDUINO) && !defined(TCXO_OPTIONAL) && RADIOLIB_EXCLUDE_SX126X != 1
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find SX1262 radio\n");
@@ -899,7 +914,7 @@ void setup()
#endif
#if defined(USE_SX1262) && !defined(ARCH_PORTDUINO) && defined(TCXO_OPTIONAL)
if (!rIf) {
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
// Try using the specified TCXO voltage
rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
@@ -915,7 +930,7 @@ void setup()
}
}
if (!rIf) {
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
// If specified TCXO voltage fails, attempt to use DIO3 as a reference instea
rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
@@ -933,7 +948,7 @@ void setup()
#endif
#if defined(USE_SX1268)
if (!rIf) {
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
rIf = new SX1268Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find SX1268 radio\n");
@@ -947,7 +962,7 @@ void setup()
#endif
#if defined(USE_LLCC68)
if (!rIf) {
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
rIf = new LLCC68Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find LLCC68 radio\n");
@@ -960,33 +975,49 @@ void setup()
}
#endif
#if defined(USE_LR1110)
if (!rIf) {
rIf = new LR1110Interface(RadioLibHAL, LR1110_SPI_NSS_PIN, LR1110_IRQ_PIN, LR1110_NRESER_PIN, LR1110_BUSY_PIN);
#if defined(USE_LR1110) && RADIOLIB_EXCLUDE_LR11X0 != 1
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
rIf = new LR1110Interface(RadioLibHAL, LR1110_SPI_NSS_PIN, LR1110_IRQ_PIN, LR1110_NRESET_PIN, LR1110_BUSY_PIN);
if (!rIf->init()) {
LOG_WARN("Failed to find LR1110 radio\n");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("LR1110 Radio init succeeded, using LR1110 radio\n");
radioType = LR1110_RADIO;
}
}
#endif
#if defined(USE_LR1120)
#if defined(USE_LR1120) && RADIOLIB_EXCLUDE_LR11X0 != 1
if (!rIf) {
rIf = new LR1120Interface(RadioLibHAL, LR1120_SPI_NSS_PIN, LR1120_IRQ_PIN, LR1120_NRESER_PIN, LR1120_BUSY_PIN);
rIf = new LR1120Interface(RadioLibHAL, LR1120_SPI_NSS_PIN, LR1120_IRQ_PIN, LR1120_NRESET_PIN, LR1120_BUSY_PIN);
if (!rIf->init()) {
LOG_WARN("Failed to find LR1120 radio\n");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("LR1120 Radio init succeeded, using LR1120 radio\n");
radioType = LR1120_RADIO;
}
}
#endif
#if defined(USE_SX1280)
#if defined(USE_LR1121) && RADIOLIB_EXCLUDE_LR11X0 != 1
if (!rIf) {
rIf = new LR1121Interface(RadioLibHAL, LR1121_SPI_NSS_PIN, LR1121_IRQ_PIN, LR1121_NRESET_PIN, LR1121_BUSY_PIN);
if (!rIf->init()) {
LOG_WARN("Failed to find LR1121 radio\n");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("LR1121 Radio init succeeded, using LR1121 radio\n");
radioType = LR1121_RADIO;
}
}
#endif
#if defined(USE_SX1280) && RADIOLIB_EXCLUDE_SX128X != 1
if (!rIf) {
rIf = new SX1280Interface(RadioLibHAL, SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY);
if (!rIf->init()) {
@@ -1001,7 +1032,6 @@ void setup()
#endif
// check if the radio chip matches the selected region
if ((config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLora())) {
LOG_WARN("Radio chip does not support 2.4GHz LoRa. Reverting to unset.\n");
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
@@ -1093,6 +1123,9 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
deviceMetadata.position_flags = config.position.position_flags;
deviceMetadata.hw_model = HW_VENDOR;
deviceMetadata.hasRemoteHardware = moduleConfig.remote_hardware.enabled;
#if !(MESHTASTIC_EXCLUDE_PKI)
deviceMetadata.hasPKC = true;
#endif
return deviceMetadata;
}
#ifndef PIO_UNIT_TESTING
@@ -1100,10 +1133,6 @@ void loop()
{
runASAP = false;
// axpDebugOutput.loop();
// heap_caps_check_integrity_all(true); // FIXME - disable this expensive check
#ifdef ARCH_ESP32
esp32Loop();
#endif
@@ -1112,33 +1141,21 @@ void loop()
#endif
powerCommandsCheck();
// For debugging
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
#ifdef DEBUG_STACK
static uint32_t lastPrint = 0;
if (millis() - lastPrint > 10 * 1000L) {
if (!Throttle::isWithinTimespanMs(lastPrint, 10 * 1000L)) {
lastPrint = millis();
meshtastic::printThreadInfo("main");
}
#endif
// TODO: This should go into a thread handled by FreeRTOS.
// handleWebResponse();
service->loop();
long delayMsec = mainController.runOrDelay();
/* if (mainController.nextThread && delayMsec)
LOG_DEBUG("Next %s in %ld\n", mainController.nextThread->ThreadName.c_str(),
mainController.nextThread->tillRun(millis())); */
// We want to sleep as long as possible here - because it saves power
if (!runASAP && loopCanSleep()) {
// if(delayMsec > 100) LOG_DEBUG("sleeping %ld\n", delayMsec);
mainDelay.delay(delayMsec);
}
// if (didWake) LOG_DEBUG("wake!\n");
}
#endif

View File

@@ -56,8 +56,8 @@ extern AudioThread *audioThread;
// Global Screen singleton.
extern graphics::Screen *screen;
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
#include "AccelerometerThread.h"
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C
#include "motion/AccelerometerThread.h"
extern AccelerometerThread *accelerometerThread;
#endif
@@ -86,4 +86,4 @@ void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearB
meshtastic_DeviceMetadata getDeviceMetadata();
// We default to 4MHz SPI, SPI mode 0
extern SPISettings spiSettings;
extern SPISettings spiSettings;

View File

@@ -57,6 +57,8 @@ uint32_t MemGet::getFreePsram()
{
#ifdef ARCH_ESP32
return ESP.getFreePsram();
#elif defined(ARCH_PORTDUINO)
return 4194252;
#else
return 0;
#endif
@@ -71,6 +73,8 @@ uint32_t MemGet::getPsramSize()
{
#ifdef ARCH_ESP32
return ESP.getPsramSize();
#elif defined(ARCH_PORTDUINO)
return 4194252;
#else
return 0;
#endif

View File

@@ -69,9 +69,9 @@ bool CryptoEngine::encryptCurve25519(uint32_t toNode, uint32_t fromNode, uint64_
uint32_t *extraNonce;
long extraNonceTmp = random();
auth = bytesOut + numBytes;
extraNonce = (uint32_t *)(auth + 8);
*extraNonce = extraNonceTmp;
LOG_INFO("Random nonce value: %d\n", *extraNonce);
memcpy((uint8_t *)(auth + 8), &extraNonceTmp,
sizeof(uint32_t)); // do not use dereference on potential non aligned pointers : *extraNonce = extraNonceTmp;
LOG_INFO("Random nonce value: %d\n", extraNonceTmp);
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(toNode);
if (node->num < 1 || node->user.public_key.size == 0) {
LOG_DEBUG("Node %d or their public_key not found\n", toNode);
@@ -80,14 +80,15 @@ bool CryptoEngine::encryptCurve25519(uint32_t toNode, uint32_t fromNode, uint64_
if (!crypto->setDHKey(toNode)) {
return false;
}
initNonce(fromNode, packetNum, *extraNonce);
initNonce(fromNode, packetNum, extraNonceTmp);
// Calculate the shared secret with the destination node and encrypt
printBytes("Attempting encrypt using nonce: ", nonce, 13);
printBytes("Attempting encrypt using shared_key: ", shared_key, 32);
printBytes("Attempting encrypt using shared_key starting with: ", shared_key, 8);
aes_ccm_ae(shared_key, 32, nonce, 8, bytes, numBytes, nullptr, 0, bytesOut,
auth); // this can write up to 15 bytes longer than numbytes past bytesOut
*extraNonce = extraNonceTmp;
memcpy((uint8_t *)(auth + 8), &extraNonceTmp,
sizeof(uint32_t)); // do not use dereference on potential non aligned pointers : *extraNonce = extraNonceTmp;
return true;
}
@@ -99,11 +100,13 @@ bool CryptoEngine::encryptCurve25519(uint32_t toNode, uint32_t fromNode, uint64_
*/
bool CryptoEngine::decryptCurve25519(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes, uint8_t *bytesOut)
{
uint8_t *auth; // set to last 8 bytes of text?
uint32_t *extraNonce;
uint8_t *auth; // set to last 8 bytes of text?
uint32_t extraNonce; // pointer was not really used
auth = bytes + numBytes - 12;
extraNonce = (uint32_t *)(auth + 8);
LOG_INFO("Random nonce value: %d\n", *extraNonce);
#ifndef PIO_UNIT_TESTING
memcpy(&extraNonce, auth + 8,
sizeof(uint32_t)); // do not use dereference on potential non aligned pointers : (uint32_t *)(auth + 8);
LOG_INFO("Random nonce value: %d\n", extraNonce);
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(fromNode);
if (node == nullptr || node->num < 1 || node->user.public_key.size == 0) {
@@ -115,9 +118,10 @@ bool CryptoEngine::decryptCurve25519(uint32_t fromNode, uint64_t packetNum, size
if (!crypto->setDHKey(fromNode)) {
return false;
}
initNonce(fromNode, packetNum, *extraNonce);
#endif
initNonce(fromNode, packetNum, extraNonce);
printBytes("Attempting decrypt using nonce: ", nonce, 13);
printBytes("Attempting decrypt using shared_key: ", shared_key, 32);
printBytes("Attempting decrypt using shared_key starting with: ", shared_key, 8);
return aes_ccm_ad(shared_key, 32, nonce, 8, bytes, numBytes - 12, nullptr, 0, auth, bytesOut);
}
@@ -137,11 +141,12 @@ bool CryptoEngine::setDHKey(uint32_t nodeNum)
LOG_DEBUG("Node %d or their public_key not found\n", nodeNum);
return false;
}
printBytes("Generating DH with remote pubkey: ", node->user.public_key.bytes, 32);
printBytes("And local pubkey: ", config.security.public_key.bytes, 32);
if (!setDHPublicKey(node->user.public_key.bytes))
return false;
printBytes("DH Output: ", shared_key, 32);
// printBytes("DH Output: ", shared_key, 32);
/**
* D.J. Bernstein reccomends hashing the shared key. We want to do this because there are
@@ -166,12 +171,12 @@ bool CryptoEngine::setDHKey(uint32_t nodeNum)
void CryptoEngine::hash(uint8_t *bytes, size_t numBytes)
{
SHA256 hash;
size_t posn, len;
size_t posn;
uint8_t size = numBytes;
uint8_t inc = 16;
hash.reset();
for (posn = 0; posn < size; posn += inc) {
len = size - posn;
size_t len = size - posn;
if (len > inc)
len = inc;
hash.update(bytes + posn, len);

View File

@@ -3,6 +3,8 @@
#include <cstdint>
#define ONE_DAY 24 * 60 * 60
#define ONE_MINUTE_MS 60 * 1000
#define THIRTY_SECONDS_MS 30 * 1000
#define FIVE_SECONDS_MS 5 * 1000
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 30 * 60)

View File

@@ -8,12 +8,19 @@
#include "api/ServerAPI.h"
// We need this declaration for proper linking in derived classes
#if RADIOLIB_EXCLUDE_SX126X != 1
template class SX126xInterface<SX1262>;
template class SX126xInterface<SX1268>;
template class SX126xInterface<LLCC68>;
#endif
#if RADIOLIB_EXCLUDE_SX128X != 1
template class SX128xInterface<SX1280>;
#endif
#if RADIOLIB_EXCLUDE_LR11X0 != 1
template class LR11x0Interface<LR1110>;
template class LR11x0Interface<LR1120>;
template class LR11x0Interface<LR1121>;
#endif
#ifdef ARCH_STM32WL
template class SX126xInterface<STM32WLx>;
#endif

View File

@@ -1,3 +1,4 @@
#if RADIOLIB_EXCLUDE_SX126X != 1
#include "LLCC68Interface.h"
#include "configuration.h"
#include "error.h"
@@ -6,4 +7,5 @@ LLCC68Interface::LLCC68Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, R
RADIOLIB_PIN_TYPE busy)
: SX126xInterface(hal, cs, irq, rst, busy)
{
}
}
#endif

View File

@@ -1,5 +1,5 @@
#pragma once
#if RADIOLIB_EXCLUDE_SX126X != 1
#include "SX126xInterface.h"
/**
@@ -15,4 +15,5 @@ class LLCC68Interface : public SX126xInterface<LLCC68>
public:
LLCC68Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
RADIOLIB_PIN_TYPE busy);
};
};
#endif

View File

@@ -1,3 +1,5 @@
#if RADIOLIB_EXCLUDE_LR11X0 != 1
#include "LR1110Interface.h"
#include "configuration.h"
#include "error.h"
@@ -6,4 +8,5 @@ LR1110Interface::LR1110Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, R
RADIOLIB_PIN_TYPE busy)
: LR11x0Interface(hal, cs, irq, rst, busy)
{
}
}
#endif

View File

@@ -1,5 +1,5 @@
#pragma once
#if RADIOLIB_EXCLUDE_LR11X0 != 1
#include "LR11x0Interface.h"
/**
@@ -10,4 +10,5 @@ class LR1110Interface : public LR11x0Interface<LR1110>
public:
LR1110Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
RADIOLIB_PIN_TYPE busy);
};
};
#endif

View File

@@ -1,3 +1,5 @@
#if RADIOLIB_EXCLUDE_LR11X0 != 1
#include "LR1120Interface.h"
#include "configuration.h"
#include "error.h"
@@ -6,4 +8,10 @@ LR1120Interface::LR1120Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, R
RADIOLIB_PIN_TYPE busy)
: LR11x0Interface(hal, cs, irq, rst, busy)
{
}
}
bool LR1120Interface::wideLora()
{
return true;
}
#endif

View File

@@ -1,7 +1,7 @@
#pragma once
#if RADIOLIB_EXCLUDE_LR11X0 != 1
#include "LR11x0Interface.h"
/**
* Our adapter for LR1120 wideband radios
*/
@@ -10,4 +10,6 @@ class LR1120Interface : public LR11x0Interface<LR1120>
public:
LR1120Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
RADIOLIB_PIN_TYPE busy);
};
bool wideLora() override;
};
#endif

View File

@@ -0,0 +1,16 @@
#if RADIOLIB_EXCLUDE_LR11X0 != 1
#include "LR1121Interface.h"
#include "configuration.h"
#include "error.h"
LR1121Interface::LR1121Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
RADIOLIB_PIN_TYPE busy)
: LR11x0Interface(hal, cs, irq, rst, busy)
{
}
bool LR1121Interface::wideLora()
{
return true;
}
#endif

View File

@@ -0,0 +1,16 @@
#pragma once
#if RADIOLIB_EXCLUDE_LR11X0 != 1
#include "LR11x0Interface.h"
/**
* Our adapter for LR1121 wideband radios
*/
class LR1121Interface : public LR11x0Interface<LR1121>
{
public:
LR1121Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
RADIOLIB_PIN_TYPE busy);
bool wideLora() override;
};
#endif

View File

@@ -1,15 +1,33 @@
#if RADIOLIB_EXCLUDE_LR11X0 != 1
#include "LR11x0Interface.h"
#include "Throttle.h"
#include "configuration.h"
#include "error.h"
#include "mesh/NodeDB.h"
#ifdef LR11X0_DIO_AS_RF_SWITCH
#include "rfswitch.h"
#else
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
static const Module::RfSwitchMode_t rfswitch_table[] = {
{LR11x0::MODE_STBY, {}}, {LR11x0::MODE_RX, {}}, {LR11x0::MODE_TX, {}}, {LR11x0::MODE_TX_HP, {}},
{LR11x0::MODE_TX_HF, {}}, {LR11x0::MODE_GNSS, {}}, {LR11x0::MODE_WIFI, {}}, END_OF_MODE_TABLE,
};
#endif
#ifdef ARCH_PORTDUINO
#include "PortduinoGlue.h"
#endif
// Particular boards might define a different max power based on what their hardware can do, default to max power output if not
// specified (may be dangerous if using external PA and LR11x0 power config forgotten)
#ifndef LR11X0_MAX_POWER
#define LR11X0_MAX_POWER 22
#ifndef LR1110_MAX_POWER
#define LR1110_MAX_POWER 22
#endif
// the 2.4G part maxes at 13dBm
#ifndef LR1120_MAX_POWER
#define LR1120_MAX_POWER 13
#endif
template <typename T>
@@ -45,59 +63,15 @@ template <typename T> bool LR11x0Interface<T>::init()
RadioLibInterface::init();
if (power > LR11X0_MAX_POWER) // Clamp power to maximum defined level
power = LR11X0_MAX_POWER;
if (power > LR1110_MAX_POWER) // Clamp power to maximum defined level
power = LR1110_MAX_POWER;
if ((power > LR1120_MAX_POWER) &&
(config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) // clamp again if wide freq range
power = LR1120_MAX_POWER;
limitPower();
#ifdef TRACKER_T1000_E // Tracker T1000E uses DIO5, DIO6, DIO7, DIO8 for RF switching
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_LR11X0_DIO7,
RADIOLIB_LR11X0_DIO8, RADIOLIB_NC};
static const Module::RfSwitchMode_t rfswitch_table[] = {
// mode DIO5 DIO6 DIO7 DIO8
{LR11x0::MODE_STBY, {LOW, LOW, LOW, LOW}}, {LR11x0::MODE_RX, {HIGH, LOW, LOW, HIGH}},
{LR11x0::MODE_TX, {HIGH, HIGH, LOW, HIGH}}, {LR11x0::MODE_TX_HP, {LOW, HIGH, LOW, HIGH}},
{LR11x0::MODE_TX_HF, {LOW, LOW, LOW, LOW}}, {LR11x0::MODE_GNSS, {LOW, LOW, HIGH, LOW}},
{LR11x0::MODE_WIFI, {LOW, LOW, LOW, LOW}}, END_OF_MODE_TABLE,
};
#else
// set RF switch configuration for Wio WM1110
// Wio WM1110 uses DIO5 and DIO6 for RF switching
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_NC, RADIOLIB_NC,
RADIOLIB_NC};
static const Module::RfSwitchMode_t rfswitch_table[] = {
// mode DIO5 DIO6
{LR11x0::MODE_STBY, {LOW, LOW}}, {LR11x0::MODE_RX, {HIGH, LOW}},
{LR11x0::MODE_TX, {HIGH, HIGH}}, {LR11x0::MODE_TX_HP, {LOW, HIGH}},
{LR11x0::MODE_TX_HF, {LOW, LOW}}, {LR11x0::MODE_GNSS, {LOW, LOW}},
{LR11x0::MODE_WIFI, {LOW, LOW}}, END_OF_MODE_TABLE,
};
#endif
// We need to do this before begin() call
#ifdef LR11X0_DIO_AS_RF_SWITCH
LOG_DEBUG("Setting DIO RF switch\n");
bool dioAsRfSwitch = true;
#elif defined(ARCH_PORTDUINO)
bool dioAsRfSwitch = false;
if (settingsMap[dio2_as_rf_switch]) {
LOG_DEBUG("Setting DIO RF switch\n");
dioAsRfSwitch = true;
}
#else
bool dioAsRfSwitch = false;
#endif
if (dioAsRfSwitch)
lora.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table);
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
// \todo Display actual typename of the adapter, not just `LR11x0`
LOG_INFO("LR11x0 init result %d\n", res);
@@ -121,6 +95,23 @@ template <typename T> bool LR11x0Interface<T>::init()
// FIXME: May want to set depending on a definition, currently all LR1110 variant files use the DC-DC regulator option
if (res == RADIOLIB_ERR_NONE)
res = lora.setRegulatorDCDC();
#ifdef LR11X0_DIO_AS_RF_SWITCH
bool dioAsRfSwitch = true;
#elif defined(ARCH_PORTDUINO)
bool dioAsRfSwitch = false;
if (settingsMap[dio2_as_rf_switch]) {
dioAsRfSwitch = true;
}
#else
bool dioAsRfSwitch = false;
#endif
if (dioAsRfSwitch) {
lora.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table);
LOG_DEBUG("Setting DIO RF switch\n", res);
}
if (res == RADIOLIB_ERR_NONE) {
if (config.lora.sx126x_rx_boosted_gain) { // the name is unfortunate but historically accurate
res = lora.setRxBoostedGainMode(true);
@@ -172,8 +163,10 @@ template <typename T> bool LR11x0Interface<T>::reconfigure()
if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
if (power > LR11X0_MAX_POWER) // This chip has lower power limits than some
power = LR11X0_MAX_POWER;
if (power > LR1110_MAX_POWER) // This chip has lower power limits than some
power = LR1110_MAX_POWER;
if ((power > LR1120_MAX_POWER) && (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) // 2.4G power limit
power = LR1120_MAX_POWER;
err = lora.setOutputPower(power);
assert(err == RADIOLIB_ERR_NONE);
@@ -270,29 +263,8 @@ template <typename T> bool LR11x0Interface<T>::isActivelyReceiving()
{
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
// received and handled the interrupt for reading the packet/handling errors.
uint16_t irq = lora.getIrqStatus();
bool detected = (irq & (RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID | RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED));
// Handle false detections
if (detected) {
uint32_t now = millis();
if (!activeReceiveStart) {
activeReceiveStart = now;
} else if ((now - activeReceiveStart > 2 * preambleTimeMsec) && !(irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID)) {
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false preamble detection.\n");
return false;
} else if (now - activeReceiveStart > maxPacketTimeMsec) {
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false header detection.\n");
return false;
}
}
// if (detected) LOG_DEBUG("rx detected\n");
return detected;
return receiveDetected(lora.getIrqStatus(), RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID,
RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED);
}
template <typename T> bool LR11x0Interface<T>::sleep()
@@ -313,4 +285,5 @@ template <typename T> bool LR11x0Interface<T>::sleep()
#endif
return true;
}
}
#endif

View File

@@ -1,5 +1,5 @@
#pragma once
#if RADIOLIB_EXCLUDE_LR11X0 != 1
#include "RadioLibInterface.h"
/**
@@ -65,7 +65,5 @@ template <class T> class LR11x0Interface : public RadioLibInterface
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
virtual void setStandby() override;
private:
uint32_t activeReceiveStart = 0;
};
#endif

View File

@@ -79,7 +79,8 @@ class MeshModule
meshtastic_AdminMessage *response);
#if HAS_SCREEN
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
virtual bool isRequestingFocus(); // Checked by screen, when regenerating frameset
virtual bool isRequestingFocus(); // Checked by screen, when regenerating frameset
virtual bool interceptingKeyboardInput() { return false; } // Can screen use keyboard for nav, or is module handling input?
#endif
protected:
const char *name;

View File

@@ -13,9 +13,9 @@
#if defined(ARCH_PORTDUINO) && !HAS_RADIO
#include "../platform/portduino/SimRadio.h"
#endif
#ifdef ARCH_ESP32
#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
#include "modules/esp32/StoreForwardModule.h"
#include "modules/StoreForwardModule.h"
#endif
#endif
@@ -92,6 +92,9 @@ class MeshService
/// Return the next MqttClientProxyMessage packet destined to the phone.
meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); }
/// Return the next ClientNotification packet destined to the phone.
meshtastic_ClientNotification *getClientNotificationForPhone() { return toPhoneClientNotificationQueue.dequeuePtr(0); }
// search the queue for a request id and return the matching nodenum
NodeNum getNodenumFromRequestId(uint32_t request_id);

View File

@@ -32,12 +32,13 @@
#if HAS_WIFI
#include "mesh/wifi/WiFiAPClient.h"
#endif
#include "modules/esp32/StoreForwardModule.h"
#include "modules/StoreForwardModule.h"
#include <Preferences.h>
#include <nvs_flash.h>
#endif
#ifdef ARCH_PORTDUINO
#include "modules/StoreForwardModule.h"
#include "platform/portduino/PortduinoGlue.h"
#endif
@@ -49,7 +50,7 @@
NodeDB *nodeDB = nullptr;
// we have plenty of ram so statically alloc this tempbuf (for now)
EXT_RAM_ATTR meshtastic_DeviceState devicestate;
EXT_RAM_BSS_ATTR meshtastic_DeviceState devicestate;
meshtastic_MyNodeInfo &myNodeInfo = devicestate.my_node;
meshtastic_LocalConfig config;
meshtastic_LocalModuleConfig moduleConfig;
@@ -121,6 +122,8 @@ NodeDB::NodeDB()
owner.hw_model = HW_VENDOR;
// Ensure user (nodeinfo) role is set to whatever we're configured to
owner.role = config.device.role;
// Ensure macaddr is set to our macaddr as it will be copied in our info below
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
// Include our owner in the node db under our nodenum
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
@@ -129,39 +132,31 @@ NodeDB::NodeDB()
config.security.serial_enabled = config.device.serial_enabled;
config.security.is_managed = config.device.is_managed;
}
#if !(MESHTASTIC_EXCLUDE_PKI)
#if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN || MESHTASTIC_EXCLUDE_PKI)
bool keygenSuccess = false;
if (config.security.private_key.size == 32) {
if (crypto->regeneratePublicKey(config.security.public_key.bytes, config.security.private_key.bytes)) {
keygenSuccess = true;
}
} else {
LOG_INFO("Generating new PKI keys\n");
crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes);
keygenSuccess = true;
}
if (keygenSuccess) {
config.security.public_key.size = 32;
config.security.private_key.size = 32;
owner.public_key.size = 32;
memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32);
}
#elif !(MESHTASTIC_EXCLUDE_PKI)
// Calculate Curve25519 public and private keys
printBytes("Old Pubkey", config.security.public_key.bytes, 32);
if (config.security.private_key.size == 32 && config.security.public_key.size == 32) {
LOG_INFO("Using saved PKI keys\n");
owner.public_key.size = config.security.public_key.size;
memcpy(owner.public_key.bytes, config.security.public_key.bytes, config.security.public_key.size);
crypto->setDHPrivateKey(config.security.private_key.bytes);
} else {
#if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN)
bool keygenSuccess = false;
if (config.security.private_key.size == 32) {
LOG_INFO("Calculating PKI Public Key\n");
if (crypto->regeneratePublicKey(config.security.public_key.bytes, config.security.private_key.bytes)) {
keygenSuccess = true;
}
} else {
LOG_INFO("Generating new PKI keys\n");
crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes);
keygenSuccess = true;
}
if (keygenSuccess) {
config.security.public_key.size = 32;
config.security.private_key.size = 32;
printBytes("New Pubkey", config.security.public_key.bytes, 32);
owner.public_key.size = 32;
memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32);
}
#else
LOG_INFO("No PKI keys set, and generation disabled!\n");
#endif
}
#endif
info->user = TypeConversions::ConvertToUserLite(owner);
@@ -243,7 +238,7 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
#endif
// second, install default state (this will deal with the duplicate mac address issue)
installDefaultDeviceState();
installDefaultConfig();
installDefaultConfig(!eraseBleBonds); // Also preserve the private key if we're not erasing BLE bonds
installDefaultModuleConfig();
installDefaultChannels();
// third, write everything to disk
@@ -266,8 +261,13 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
return true;
}
void NodeDB::installDefaultConfig()
void NodeDB::installDefaultConfig(bool preserveKey = false)
{
uint8_t private_key_temp[32];
bool shouldPreserveKey = preserveKey && config.has_security && config.security.private_key.size > 0;
if (shouldPreserveKey) {
memcpy(private_key_temp, config.security.private_key.bytes, config.security.private_key.size);
}
LOG_INFO("Installing default LocalConfig\n");
memset(&config, 0, sizeof(meshtastic_LocalConfig));
config.version = DEVICESTATE_CUR_VER;
@@ -308,8 +308,14 @@ void NodeDB::installDefaultConfig()
#else
config.security.admin_key[0].size = 0;
#endif
if (shouldPreserveKey) {
config.security.private_key.size = 32;
memcpy(config.security.private_key.bytes, private_key_temp, config.security.private_key.size);
printBytes("Restored key", config.security.private_key.bytes, config.security.private_key.size);
} else {
config.security.private_key.size = 0;
}
config.security.public_key.size = 0;
config.security.private_key.size = 0;
#ifdef PIN_GPS_EN
config.position.gps_en_gpio = PIN_GPS_EN;
#endif
@@ -459,7 +465,7 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.has_detection_sensor = true;
moduleConfig.detection_sensor.enabled = false;
moduleConfig.detection_sensor.detection_triggered_high = true;
moduleConfig.detection_sensor.detection_trigger_type = meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_LOGIC_HIGH;
moduleConfig.detection_sensor.minimum_broadcast_secs = 45;
moduleConfig.has_ambient_lighting = true;
@@ -641,10 +647,13 @@ void NodeDB::pickNewNodeNum()
}
meshtastic_NodeInfoLite *found;
while ((nodeNum == NODENUM_BROADCAST || nodeNum < NUM_RESERVED) ||
((found = getMeshNode(nodeNum)) && memcmp(found->user.macaddr, ourMacAddr, sizeof(ourMacAddr)) != 0)) {
while (((found = getMeshNode(nodeNum)) && memcmp(found->user.macaddr, ourMacAddr, sizeof(ourMacAddr)) != 0) ||
(nodeNum == NODENUM_BROADCAST || nodeNum < NUM_RESERVED)) {
NodeNum candidate = random(NUM_RESERVED, LONG_MAX); // try a new random choice
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, so trying for 0x%x\n", nodeNum, candidate);
if (found)
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, by MAC ending in 0x%02x%02x vs our 0x%02x%02x, so "
"trying for 0x%x\n",
nodeNum, found->user.macaddr[4], found->user.macaddr[5], ourMacAddr[4], ourMacAddr[5], candidate);
nodeNum = candidate;
}
LOG_DEBUG("Using nodenum 0x%x \n", nodeNum);
@@ -710,7 +719,7 @@ void NodeDB::loadFromDisk()
//} else {
if (devicestate.version < DEVICESTATE_MIN_VER) {
LOG_WARN("Devicestate %d is old, discarding\n", devicestate.version);
factoryReset();
installDefaultDeviceState();
} else {
LOG_INFO("Loaded saved devicestate version %d, with nodecount: %d\n", devicestate.version,
devicestate.node_db_lite.size());
@@ -726,7 +735,7 @@ void NodeDB::loadFromDisk()
} else {
if (config.version < DEVICESTATE_MIN_VER) {
LOG_WARN("config %d is old, discarding\n", config.version);
installDefaultConfig();
installDefaultConfig(true);
} else {
LOG_INFO("Loaded saved config version %d\n", config.version);
}
@@ -1039,7 +1048,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
if (p.public_key.size > 0) {
printBytes("Incoming Pubkey: ", p.public_key.bytes, 32);
if (info->user.public_key.size > 0) { // if we have a key for this user already, don't overwrite with a new one
LOG_INFO("Public Key set for node, not updateing!\n");
LOG_INFO("Public Key set for node, not updating!\n");
// we copy the key into the incoming packet, to prevent overwrite
memcpy(p.public_key.bytes, info->user.public_key.bytes, 32);
} else {
@@ -1097,8 +1106,10 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT
// If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway
if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start)
if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) {
info->has_hops_away = true;
info->hops_away = mp.hop_start - mp.hop_limit;
}
}
}
@@ -1194,4 +1205,4 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co
LOG_ERROR("A critical failure occurred, portduino is exiting...");
exit(2);
#endif
}
}

View File

@@ -2,11 +2,13 @@
#include "Observer.h"
#include <Arduino.h>
#include <algorithm>
#include <assert.h>
#include <vector>
#include "MeshTypes.h"
#include "NodeStatus.h"
#include "configuration.h"
#include "mesh-pb-constants.h"
#include "mesh/generated/meshtastic/mesh.pb.h" // For CriticalErrorCode
@@ -182,7 +184,8 @@ class NodeDB
void cleanupMeshDB();
/// Reinit device state from scratch (not loading from disk)
void installDefaultDeviceState(), installDefaultChannels(), installDefaultConfig(), installDefaultModuleConfig();
void installDefaultDeviceState(), installDefaultChannels(), installDefaultConfig(bool preserveKey),
installDefaultModuleConfig();
/// write to flash
/// @return true if the save was successful

View File

@@ -5,6 +5,7 @@
#ifdef ARCH_PORTDUINO
#include "platform/portduino/PortduinoGlue.h"
#endif
#include "Throttle.h"
PacketHistory::PacketHistory()
{
@@ -22,18 +23,17 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd
return false; // Not a floodable message ID, so we don't care
}
uint32_t now = millis();
PacketRecord r;
r.id = p->id;
r.sender = getFrom(p);
r.rxTimeMsec = now;
r.rxTimeMsec = millis();
auto found = recentPackets.find(r);
bool seenRecently = (found != recentPackets.end()); // found not equal to .end() means packet was seen recently
if (seenRecently && (now - found->rxTimeMsec) >= FLOOD_EXPIRE_TIME) { // Check whether found packet has already expired
recentPackets.erase(found); // Erase and pretend packet has not been seen recently
if (seenRecently &&
!Throttle::isWithinTimespanMs(found->rxTimeMsec, FLOOD_EXPIRE_TIME)) { // Check whether found packet has already expired
recentPackets.erase(found); // Erase and pretend packet has not been seen recently
found = recentPackets.end();
seenRecently = false;
}
@@ -64,12 +64,10 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd
*/
void PacketHistory::clearExpiredRecentPackets()
{
uint32_t now = millis();
LOG_DEBUG("recentPackets size=%ld\n", recentPackets.size());
for (auto it = recentPackets.begin(); it != recentPackets.end();) {
if ((now - it->rxTimeMsec) >= FLOOD_EXPIRE_TIME) {
if (!Throttle::isWithinTimespanMs(it->rxTimeMsec, FLOOD_EXPIRE_TIME)) {
it = recentPackets.erase(it); // erase returns iterator pointing to element immediately following the one erased
} else {
++it;

View File

@@ -8,6 +8,7 @@
#include "FSCommon.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "PacketHistory.h"
#include "PhoneAPI.h"
#include "PowerFSM.h"
#include "RadioInterface.h"
@@ -25,10 +26,13 @@
#if !MESHTASTIC_EXCLUDE_MQTT
#include "mqtt/MQTT.h"
#endif
#include "Throttle.h"
#include <RTC.h>
PhoneAPI::PhoneAPI()
{
lastContactMsec = millis();
std::fill(std::begin(recentToRadioPacketIds), std::end(recentToRadioPacketIds), 0);
}
PhoneAPI::~PhoneAPI()
@@ -60,9 +64,11 @@ void PhoneAPI::handleStartConfig()
void PhoneAPI::close()
{
LOG_INFO("PhoneAPI::close()\n");
if (state != STATE_SEND_NOTHING) {
state = STATE_SEND_NOTHING;
resetReadIndex();
unobserve(&service->fromNumChanged);
#ifdef FSCom
unobserve(&xModem.packetReady);
@@ -70,8 +76,17 @@ void PhoneAPI::close()
releasePhonePacket(); // Don't leak phone packets on shutdown
releaseQueueStatusPhonePacket();
releaseMqttClientProxyPhonePacket();
releaseClientNotification();
onConnectionChanged(false);
fromRadioScratch = {};
toRadioScratch = {};
nodeInfoForPhone = {};
packetForPhone = NULL;
filesManifest.clear();
fromRadioNum = 0;
config_nonce = 0;
config_state = 0;
pauseBluetoothLogging = false;
}
}
@@ -96,8 +111,6 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep
lastContactMsec = millis();
// return (lastContactMsec != 0) &&
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
if (pb_decode_from_bytes(buf, bufLength, &meshtastic_ToRadio_msg, &toRadioScratch)) {
switch (toRadioScratch.which_payload_variant) {
@@ -194,7 +207,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
auto us = nodeDB->readNextMeshNode(readIndex);
if (us) {
nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(us);
nodeInfoForPhone.hops_away = 0;
nodeInfoForPhone.has_hops_away = false;
nodeInfoForPhone.is_favorite = true;
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag;
fromRadioScratch.node_info = nodeInfoForPhone;
@@ -403,6 +416,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_xmodemPacket_tag;
fromRadioScratch.xmodemPacket = xmodemPacketForPhone;
xmodemPacketForPhone = meshtastic_XModem_init_zero;
} else if (clientNotification) {
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_clientNotification_tag;
fromRadioScratch.clientNotification = *clientNotification;
releaseClientNotification();
} else if (packetForPhone) {
printPacket("phone downloaded packet", packetForPhone);
@@ -442,13 +459,6 @@ void PhoneAPI::sendConfigComplete()
pauseBluetoothLogging = false;
}
void PhoneAPI::handleDisconnect()
{
filesManifest.clear();
pauseBluetoothLogging = false;
LOG_INFO("PhoneAPI disconnect\n");
}
void PhoneAPI::releasePhonePacket()
{
if (packetForPhone) {
@@ -473,6 +483,14 @@ void PhoneAPI::releaseMqttClientProxyPhonePacket()
}
}
void PhoneAPI::releaseClientNotification()
{
if (clientNotification) {
service->releaseClientNotificationToPool(clientNotification);
clientNotification = NULL;
}
}
/**
* Return true if we have data available to send to the phone
*/
@@ -507,7 +525,9 @@ bool PhoneAPI::available()
queueStatusPacketForPhone = service->getQueueStatusForPhone();
if (!mqttClientProxyMessageForPhone)
mqttClientProxyMessageForPhone = service->getMqttClientProxyMessageForPhone();
bool hasPacket = !!queueStatusPacketForPhone || !!mqttClientProxyMessageForPhone;
if (!clientNotification)
clientNotification = service->getClientNotificationForPhone();
bool hasPacket = !!queueStatusPacketForPhone || !!mqttClientProxyMessageForPhone || !!clientNotification;
if (hasPacket)
return true;
@@ -541,14 +561,64 @@ bool PhoneAPI::available()
return false;
}
void PhoneAPI::sendNotification(meshtastic_LogRecord_Level level, uint32_t replyId, const char *message)
{
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->has_reply_id = true;
cn->reply_id = replyId;
cn->level = meshtastic_LogRecord_Level_WARNING;
cn->time = getValidTime(RTCQualityFromNet);
strncpy(cn->message, message, sizeof(cn->message));
service->sendClientNotification(cn);
}
bool PhoneAPI::wasSeenRecently(uint32_t id)
{
for (int i = 0; i < 20; i++) {
if (recentToRadioPacketIds[i] == id) {
return true;
}
if (recentToRadioPacketIds[i] == 0) {
recentToRadioPacketIds[i] = id;
return false;
}
}
// If the array is full, shift all elements to the left and add the new id at the end
memmove(recentToRadioPacketIds, recentToRadioPacketIds + 1, (19) * sizeof(uint32_t));
recentToRadioPacketIds[19] = id;
return false;
}
/**
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
*/
bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
{
printPacket("PACKET FROM PHONE", &p);
service->handleToRadio(p);
if (p.id > 0 && wasSeenRecently(p.id)) {
LOG_DEBUG("Ignoring packet from phone, already seen recently\n");
return false;
}
if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && lastPortNumToRadio[p.decoded.portnum] &&
Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], THIRTY_SECONDS_MS)) {
LOG_WARN("Rate limiting portnum %d\n", p.decoded.portnum);
sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "TraceRoute can only be sent once every 30 seconds");
meshtastic_QueueStatus qs = router->getQueueStatus();
service->sendQueueStatusToPhone(qs, 0, p.id);
return false;
} else if (p.decoded.portnum == meshtastic_PortNum_POSITION_APP && lastPortNumToRadio[p.decoded.portnum] &&
Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], FIVE_SECONDS_MS)) {
LOG_WARN("Rate limiting portnum %d\n", p.decoded.portnum);
meshtastic_QueueStatus qs = router->getQueueStatus();
service->sendQueueStatusToPhone(qs, 0, p.id);
// FIXME: Figure out why this continues to happen
// sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Position can only be sent once every 5 seconds");
return false;
}
lastPortNumToRadio[p.decoded.portnum] = millis();
service->handleToRadio(p);
return true;
}

View File

@@ -2,8 +2,10 @@
#include "Observer.h"
#include "mesh-pb-constants.h"
#include "meshtastic/portnums.pb.h"
#include <iterator>
#include <string>
#include <unordered_map>
#include <vector>
// Make sure that we never let our packets grow too large for one BLE packet
@@ -48,6 +50,10 @@ class PhoneAPI
uint8_t config_state = 0;
// Hashmap of timestamps for last time we received a packet on the API per portnum
std::unordered_map<meshtastic_PortNum, uint32_t> lastPortNumToRadio;
uint32_t recentToRadioPacketIds[20]; // Last 20 ToRadio MeshPacket IDs we have seen
/**
* Each packet sent to the phone has an incrementing count
*/
@@ -99,6 +105,11 @@ class PhoneAPI
*/
virtual bool handleToRadio(const uint8_t *buf, size_t len);
/**
* Send a (client)notification to the phone
*/
virtual void sendNotification(meshtastic_LogRecord_Level level, uint32_t replyId, const char *message);
/**
* Get the next packet we want to send to the phone
*
@@ -137,11 +148,6 @@ class PhoneAPI
*/
virtual void onNowHasData(uint32_t fromRadioNum) {}
/**
* Subclasses can use this to find out when a client drops the link
*/
virtual void handleDisconnect();
private:
void releasePhonePacket();
@@ -149,9 +155,13 @@ class PhoneAPI
void releaseMqttClientProxyPhonePacket();
void releaseClientNotification();
/// begin a new connection
void handleStartConfig();
bool wasSeenRecently(uint32_t packetId);
/**
* Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it
* @return true true if a packet was queued for sending

View File

@@ -108,7 +108,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
T *decoded = NULL;
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.decoded.portnum == ourPortNum) {
memset(&scratch, 0, sizeof(scratch));
auto &p = mp.decoded;
const meshtastic_Data &p = mp.decoded;
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) {
decoded = &scratch;
} else {

View File

@@ -1,3 +1,4 @@
#if RADIOLIB_EXCLUDE_SX127X != 1
#include "RF95Interface.h"
#include "MeshRadio.h" // kinda yucky, but we need to know which region we are in
#include "RadioLibRF95.h"
@@ -336,3 +337,4 @@ bool RF95Interface::sleep()
return true;
}
#endif

View File

@@ -1,5 +1,5 @@
#pragma once
#if RADIOLIB_EXCLUDE_SX127X != 1
#include "MeshRadio.h" // kinda yucky, but we need to know which region we are in
#include "RadioLibInterface.h"
#include "RadioLibRF95.h"
@@ -69,3 +69,4 @@ class RF95Interface : public RadioLibInterface
/** Some boards require GPIO control of tx vs rx paths */
void setTransmitEnable(bool txon);
};
#endif

View File

@@ -151,7 +151,7 @@ const RegionInfo regions[] = {
const RegionInfo *myRegion;
bool RadioInterface::uses_default_frequency_slot = true;
static uint8_t bytes[MAX_RHPACKETLEN];
static uint8_t bytes[MAX_LORA_PAYLOAD_LEN + 1];
void initRegion()
{
@@ -326,7 +326,7 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p)
RadioInterface::RadioInterface()
{
assert(sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
assert(sizeof(PacketHeader) == MESHTASTIC_HEADER_LENGTH); // make sure the compiler did what we expected
}
bool RadioInterface::reconfigure()
@@ -595,26 +595,25 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
lastTxStart = millis();
PacketHeader *h = (PacketHeader *)radiobuf;
h->from = p->from;
h->to = p->to;
h->id = p->id;
h->channel = p->channel;
h->next_hop = 0; // *** For future use ***
h->relay_node = 0; // *** For future use ***
radioBuffer.header.from = p->from;
radioBuffer.header.to = p->to;
radioBuffer.header.id = p->id;
radioBuffer.header.channel = p->channel;
radioBuffer.header.next_hop = 0; // *** For future use ***
radioBuffer.header.relay_node = 0; // *** For future use ***
if (p->hop_limit > HOP_MAX) {
LOG_WARN("hop limit %d is too high, setting to %d\n", p->hop_limit, HOP_RELIABLE);
p->hop_limit = HOP_RELIABLE;
}
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0) | (p->via_mqtt ? PACKET_FLAGS_VIA_MQTT_MASK : 0);
h->flags |= (p->hop_start << PACKET_FLAGS_HOP_START_SHIFT) & PACKET_FLAGS_HOP_START_MASK;
radioBuffer.header.flags =
p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0) | (p->via_mqtt ? PACKET_FLAGS_VIA_MQTT_MASK : 0);
radioBuffer.header.flags |= (p->hop_start << PACKET_FLAGS_HOP_START_SHIFT) & PACKET_FLAGS_HOP_START_MASK;
// if the sender nodenum is zero, that means uninitialized
assert(h->from);
assert(radioBuffer.header.from);
memcpy(radiobuf + sizeof(PacketHeader), p->encrypted.bytes, p->encrypted.size);
memcpy(radioBuffer.payload, p->encrypted.bytes, p->encrypted.size);
sendingPacket = p;
return p->encrypted.size + sizeof(PacketHeader);
}
}

View File

@@ -9,7 +9,9 @@
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
#define MAX_RHPACKETLEN 256
#define MAX_LORA_PAYLOAD_LEN 255 // max length of 255 per Semtech's datasheets on SX12xx
#define MESHTASTIC_HEADER_LENGTH 16
#define MESHTASTIC_PKC_OVERHEAD 12
#define PACKET_FLAGS_HOP_LIMIT_MASK 0x07
#define PACKET_FLAGS_WANT_ACK_MASK 0x08
@@ -43,6 +45,20 @@ typedef struct {
uint8_t relay_node;
} PacketHeader;
/**
* This structure represent the structured buffer : a PacketHeader then the payload. The whole is
* MAX_LORA_PAYLOAD_LEN + 1 length
* It makes the use of its data easier, and avoids manipulating pointers (and potential non aligned accesses)
*/
typedef struct {
/** The header, as defined just before */
PacketHeader header;
/** The payload, of maximum length minus the header, aligned just to be sure */
uint8_t payload[MAX_LORA_PAYLOAD_LEN + 1 - sizeof(PacketHeader)] __attribute__ ((__aligned__));
} RadioBuffer;
/**
* Basic operations all radio chipsets must implement.
*
@@ -89,8 +105,7 @@ class RadioInterface
/**
* A temporary buffer used for sending/receiving packets, sized to hold the biggest buffer we might need
* */
uint8_t radiobuf[MAX_RHPACKETLEN];
RadioBuffer radioBuffer __attribute__ ((__aligned__));
/**
* Enqueue a received packet for the registered receiver
*/

View File

@@ -3,6 +3,7 @@
#include "NodeDB.h"
#include "PowerMon.h"
#include "SPILock.h"
#include "Throttle.h"
#include "configuration.h"
#include "error.h"
#include "main.h"
@@ -41,7 +42,7 @@ void LockingArduinoHal::spiTransfer(uint8_t *out, size_t len, uint8_t *in)
uint32_t start = millis();
while (digitalRead(busy)) {
if (millis() - start >= 2000) {
if (!Throttle::isWithinTimespanMs(start, 2000)) {
LOG_ERROR("GPIO mid-transfer timeout, is it connected?");
return;
}
@@ -114,7 +115,7 @@ bool RadioLibInterface::canSendImmediately()
}
// If we've been trying to send the same packet more than one minute and we haven't gotten a
// TX IRQ from the radio, the radio is probably broken.
if (busyTx && (millis() - lastTxStart > 60000)) {
if (busyTx && !Throttle::isWithinTimespanMs(lastTxStart, 60000)) {
LOG_ERROR("Hardware Failure! busyTx for more than 60s\n");
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_TRANSMIT_FAILED);
// reboot in 5 seconds when this condition occurs.
@@ -128,6 +129,28 @@ bool RadioLibInterface::canSendImmediately()
return true;
}
bool RadioLibInterface::receiveDetected(uint16_t irq, ulong syncWordHeaderValidFlag, ulong preambleDetectedFlag)
{
bool detected = (irq & (syncWordHeaderValidFlag | preambleDetectedFlag));
// Handle false detections
if (detected) {
if (!activeReceiveStart) {
activeReceiveStart = millis();
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) && !(irq & syncWordHeaderValidFlag)) {
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false preamble detection.\n");
return false;
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false header detection.\n");
return false;
}
}
return detected;
}
/// Send a packet (possibly by enquing in a private fifo). This routine will
/// later free() the packet to pool. This routine is not allowed to stall because it is called from
/// bluetooth comms code. If the txmit queue is empty it might return an error
@@ -144,7 +167,7 @@ ErrorCode RadioLibInterface::send(meshtastic_MeshPacket *p)
}
} else {
LOG_WARN("send - lora tx disable because RegionCode_Unset\n");
LOG_WARN("send - lora tx disabled because RegionCode_Unset\n");
packetPool.release(p);
return ERRNO_DISABLED;
}
@@ -356,7 +379,15 @@ void RadioLibInterface::handleReceiveInterrupt()
xmitMsec = getPacketTime(length);
int state = iface->readData(radiobuf, length);
#ifndef DISABLE_WELCOME_UNSET
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
LOG_WARN("recv - lora rx disabled because RegionCode_Unset\n");
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
return;
}
#endif
int state = iface->readData((uint8_t *)&radioBuffer, length);
if (state != RADIOLIB_ERR_NONE) {
LOG_ERROR("ignoring received packet due to error=%d\n", state);
rxBad++;
@@ -366,7 +397,6 @@ void RadioLibInterface::handleReceiveInterrupt()
} else {
// Skip the 4 headers that are at the beginning of the rxBuf
int32_t payloadLen = length - sizeof(PacketHeader);
const uint8_t *payload = radiobuf + sizeof(PacketHeader);
// check for short packets
if (payloadLen < 0) {
@@ -374,10 +404,9 @@ void RadioLibInterface::handleReceiveInterrupt()
rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
} else {
const PacketHeader *h = (PacketHeader *)radiobuf;
rxGood++;
// altered packet with "from == 0" can do Remote Node Administration without permission
if (h->from == 0) {
if (radioBuffer.header.from == 0) {
LOG_WARN("ignoring received packet without sender\n");
return;
}
@@ -387,22 +416,22 @@ void RadioLibInterface::handleReceiveInterrupt()
// nodes.
meshtastic_MeshPacket *mp = packetPool.allocZeroed();
mp->from = h->from;
mp->to = h->to;
mp->id = h->id;
mp->channel = h->channel;
mp->from = radioBuffer.header.from;
mp->to = radioBuffer.header.to;
mp->id = radioBuffer.header.id;
mp->channel = radioBuffer.header.channel;
assert(HOP_MAX <= PACKET_FLAGS_HOP_LIMIT_MASK); // If hopmax changes, carefully check this code
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_LIMIT_MASK;
mp->hop_start = (h->flags & PACKET_FLAGS_HOP_START_MASK) >> PACKET_FLAGS_HOP_START_SHIFT;
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
mp->via_mqtt = !!(h->flags & PACKET_FLAGS_VIA_MQTT_MASK);
mp->hop_limit = radioBuffer.header.flags & PACKET_FLAGS_HOP_LIMIT_MASK;
mp->hop_start = (radioBuffer.header.flags & PACKET_FLAGS_HOP_START_MASK) >> PACKET_FLAGS_HOP_START_SHIFT;
mp->want_ack = !!(radioBuffer.header.flags & PACKET_FLAGS_WANT_ACK_MASK);
mp->via_mqtt = !!(radioBuffer.header.flags & PACKET_FLAGS_VIA_MQTT_MASK);
addReceiveMetadata(mp);
mp->which_payload_variant =
meshtastic_MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
memcpy(mp->encrypted.bytes, payload, payloadLen);
memcpy(mp->encrypted.bytes, radioBuffer.payload, payloadLen);
mp->encrypted.size = payloadLen;
printPacket("Lora RX", mp);
@@ -444,7 +473,7 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
size_t numbytes = beginSending(txp);
int res = iface->startTransmit(radiobuf, numbytes);
int res = iface->startTransmit((uint8_t *)&radioBuffer, numbytes);
if (res != RADIOLIB_ERR_NONE) {
LOG_ERROR("startTransmit failed, error=%d\n", res);
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_RADIO_SPI_BUG);

Some files were not shown because too many files have changed in this diff Show More