Compare commits

..

186 Commits

Author SHA1 Message Date
Ben Meadors
f2ee0df015 Remove BMA-423 and STK8X by default (#5429)
* Remove BMA-423 by default

* STK

* Wrong macro

* Helps if you include the file
2024-11-23 17:18:22 -06:00
Thomas Göttgens
fcfb197571 try to detect dfrobot station to tell it apart from an ublox gps. (#5393) 2024-11-23 16:56:40 +01:00
Mictronics
dd7140b7a1 Fix admin key loading from userPrefs.h (#5417)
* Fix LED pinout for T-Echo board marked v1.0, date 2021-6-28

* Merge PR #420

* Fixed double and missing Default class.

* Use correct format specifier and fixed typo.

* Removed duplicate code.

* Fix error: #if with no expression

* Fix warning: extra tokens at end of #endif directive.

* Fix antenna switching logic. Complementary-pin control logic is required on the rp2040-lora board.

* Fix deprecated macros.

* Set RP2040 in dormant mode when deep sleep is triggered.

* Fix array out of bounds read.

* Admin key count needs to be set otherwise the key will be zero loaded after reset.

* Don't reset the admin key size when loading defaults. Preserve an existing key in config if possible.

* Remove log spam when reading INA voltage sensor.

* Remove static declaration for admin keys from userPrefs.h. Load hard coded admin keys in case config file has empty slots.

* Removed newlines from log.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2024-11-23 09:08:18 -06:00
Christopher Hoover
fadcbd597f Cleans up visibility in GPS.h (#5426)
Signed-off-by: Christopher Hoover <ch@murgatroid.com>
2024-11-23 06:10:09 -06:00
madeofstown
14b9a1a929 Update build-native.sh (#5415)
* Update build-native.sh

Device-install.sh and device-update.sh are not used on native platform, skip copying to release directory after build and copy native-install.sh and native-run.sh instead.

* Update build-native.sh

Skip native-run.sh copy
2024-11-23 18:06:31 +08:00
dylanli
c51a7b98bd add canned message and keyboard in indicator board (#5410)
* add canned message and keyboard in indicator board

* Added virtual keyboard macro and enabled for Indicator

* Cleanup macros by applying USE_VIRTUAL_KEYBOARD and DISPLAY_CLOCK_FRAME

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-22 18:54:06 -06:00
Ben Meadors
fdec95f9c1 Cherry pick tdeck fixes (#5422)
* Try-fix (workaround) T-Deck audio crash

* set T-Deck audio to unused 48 (mem mclk)

* swap mclk to gpio 21

* dreamcatcher: assign GPIO44 to audio mclk

---------

Co-authored-by: mverch67 <manuel.verch@gmx.de>
2024-11-22 14:25:09 -06:00
Jonathan Bennett
e6fb6b115a Seems like the last DIY board that's not "extra" (#5420) 2024-11-22 05:32:35 -06:00
Ben Meadors
d5bb32ff93 Temetry can respond to want-response for LocalStats variant (#5414) 2024-11-21 15:11:19 -06:00
Ben Meadors
f5058a9cbb Check for OkToMqtt flag presence before uplinking to MQTT (#5413)
* Check for oktomqtt flag presence before uplinking to MQTT

* Move to mqtt->onSend
2024-11-21 14:52:54 -06:00
GUVWAF
dbc5ec27f7 Temporarily disable MDNS when MQTT is enabled (#5418)
Leads to a panic
2024-11-21 14:11:50 -06:00
Michael Gjelsø
1089469f82 --web littlefswebui-* typo fix (#5416)
* Add --web

* Update device-install.bat

Forgot a "-" a few places.

* Typo fix.

* Typo fix

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: GUVWAF <78759985+GUVWAF@users.noreply.github.com>
2024-11-21 13:27:26 -06:00
Ben Meadors
fd98e9f553 Fixed NMEA sentence issue in CalTopo as well as bug with no printing all of the nodes (#5412) 2024-11-21 20:13:30 +08:00
dylanli
ccfc9e5dd9 add GPS in indicator board (#5411) 2024-11-21 19:14:35 +08:00
Michael Gjelsø
1752caaf19 --web added to device-install(.sh/.bat) (#5405)
* Add --web

* Update device-install.bat

Forgot a "-" a few places.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-21 07:21:06 +08:00
GUVWAF
364dead3aa Update platform-raspberrypi also (#5407)
* Update arduino-pico core to fix sporadic hangs

* Update platform-raspberrypi also
2024-11-20 14:53:36 -06:00
GUVWAF
154864dfbf Update arduino-pico core to fix sporadic hangs (#5406) 2024-11-20 13:18:27 -06:00
Ben Meadors
2ca3cdf837 Fix RTC time injection and consolidate position logic (#5396)
* Fix RTC time injection and consolidate position logic

* Comment out unused var warning

* Backerds
2024-11-20 07:52:39 -06:00
Ben Meadors
485c371de4 Create a specific hw_model for WisMesh Tap (#5400)
* Create a specific hw_model for WisMesh Tap

* Trunk

* HAS_ETHERNET

* Remove it altogether

* Don't need these either
2024-11-20 12:57:46 +08:00
jcyrio
a255da3cf5 Make heart emoji usable (#5403) 2024-11-20 11:31:46 +08:00
Catalin Patulea
d65dc497f2 /api/v1/fromradio: add OPTIONS handler for CORS. (#5386)
This avoids hitting the 404 Not Found handler, which breaks connection
keep-alive, so this change fixes a big performance regression for Web Client in
Chrome: https://github.com/meshtastic/firmware/issues/5385

Tested on Heltec V3.

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-19 14:33:44 -06:00
github-actions[bot]
c641bfd53c [create-pull-request] automated change (#5399)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-19 12:53:54 -06:00
jcyrio
b947b123fc fix 'symbal' typo (#5395) 2024-11-19 06:52:20 -06:00
Daniel.Cao
df1f66a6b9 Anable trace route function on wismeshtap platform (#5389) 2024-11-19 05:42:29 -06:00
jcyrio
70336f7f4f add smiley emoji (#5391)
* add smiley emoji

* clang-formatted
2024-11-19 13:25:11 +08:00
github-actions[bot]
de76caca32 [create-pull-request] automated change (#5388)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-17 19:29:43 -06:00
Michael Gjelsø
89469fcb88 Allows all 3 PKI keys to be added to userPrefs.h (#4969) and a tool. (#5368)
* more userPrefs.h

Added PKI Admin keys to userPrefs.h

* Update userPrefs.h

Allows all 3 PKI keys to be added to userPrefs.h (#4969)

* Update NodeDB.cpp

Trunk

* Update userPrefs.h

Changed wording

* Create base64_to_hex.py

A little tool for converting base64 PKI Keys to decoded byte that userPrefs.h can understand.

* more userPrefs.h

Added PKI Admin keys to userPrefs.h

* Update userPrefs.h

Allows all 3 PKI keys to be added to userPrefs.h (#4969)

* Update NodeDB.cpp

Trunk

* Update userPrefs.h

Changed wording

* Create base64_to_hex.py

A little tool for converting base64 PKI Keys to decoded byte that userPrefs.h can understand.
2024-11-17 12:36:41 -06:00
github-actions[bot]
a8357ebd52 [create-pull-request] automated change (#5380)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-17 10:51:11 -06:00
GUVWAF
0d1f9e915f Move some actions to after startTransmit() (#5383)
To minimize the time between channel scan and actual transmit
2024-11-17 10:51:01 -06:00
Ben Meadors
1a06f88dfb Cleanup static files from bad Web UI bundle on 2.5.13 release (#5376)
* Cleanup static files from bad Web UI bundle on 2.5.13 release

* Check existence first

* Esp32 is the only one we care about
2024-11-17 07:57:59 -06:00
Michael Gjelsø
a174ec7cf9 Bug fixed in ExternalNotificationModule (#5375)
While `nagging` setExternalState wasn't written to Buzzer & Vibra so output was never toggled.

Possible fix for #5348
2024-11-17 07:36:06 -06:00
Ben Meadors
37b29f6899 Add littlefswebui 2024-11-16 19:36:55 -06:00
Ben Meadors
74d0c58576 Diag 2024-11-16 06:24:10 -06:00
Ben Meadors
ca3d8da128 version tags 2024-11-16 06:22:08 -06:00
Ben Meadors
be6348388e Separate littlefs bundle 2024-11-16 06:12:45 -06:00
Ben Meadors
fdc473e5fa Trunk 2024-11-16 06:01:07 -06:00
Ben Meadors
add70b5229 Rework some things 2024-11-16 05:58:07 -06:00
Tom Fifield
1b99543a15 Typo fix in build_raspbian.yml (#5365)
s/sudp/sudo :(:(:(
2024-11-16 12:48:15 +08:00
Tom Fifield
90a3050c1f Add sudo to apt-get commands for Raspbian Build (#5364)
Without sudo, inadequate permissions to runs the commands meant
the build was failing.
2024-11-16 12:01:41 +08:00
GUVWAF
9545a10361 RP2040: Update core; add mDNS support (#5355)
* Update arduino-pico core

* RP2040: Add mDNS support

* SimpleMDNS `begin` now returns a bool

* Add `-g` option to `debug_build_flags` to link files for gdb

* RAK11310 needs old platform as well

* Change defines to specific architecture

* Core version 4.2.1 is out
2024-11-16 08:20:20 +08:00
Michael Gjelsø
d4d89447bd Adds fixed GPS, BUTTON_PIN and BLE code to userPrefs.h (#5341)
* userPrefs.h

Added FixedGPS
Added Fixed Bluetooth PIN

* Update NodeDB.cpp

Removed some un-used LOG_INFO

* Added BUTTON_PIN

* Trunk

* Variable re-naming.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-14 06:56:22 -06:00
github-actions[bot]
81172574a4 [create-pull-request] automated change (#5347)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-14 04:54:56 -06:00
Ben Meadors
295278bb12 Update version.properties 2024-11-13 18:47:46 -06:00
Ben Meadors
ec6949fdc0 Migrate NRF52 devices max nodes down to 80 for now to prevent brownouts (#5346) 2024-11-13 18:44:35 -06:00
github-actions[bot]
f4908fadd6 [create-pull-request] automated change (#5344)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-13 13:18:57 -06:00
Mictronics
528e177c62 Remove log spam when reading INA sensor. (#5345)
* Fix LED pinout for T-Echo board marked v1.0, date 2021-6-28

* Merge PR #420

* Fixed double and missing Default class.

* Use correct format specifier and fixed typo.

* Removed duplicate code.

* Fix error: #if with no expression

* Fix warning: extra tokens at end of #endif directive.

* Fix antenna switching logic. Complementary-pin control logic is required on the rp2040-lora board.

* Fix deprecated macros.

* Set RP2040 in dormant mode when deep sleep is triggered.

* Fix array out of bounds read.

* Admin key count needs to be set otherwise the key will be zero loaded after reset.

* Don't reset the admin key size when loading defaults. Preserve an existing key in config if possible.

* Remove log spam when reading INA voltage sensor.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-13 13:18:38 -06:00
Ben Meadors
73430cb582 Update version.properties (#5343) 2024-11-13 11:00:23 -06:00
Ben Meadors
3a66c738bd Revert "Decrease max nodes for NRF52 to 80 as workaround to prevent FS blowou…" (#5340)
This reverts commit ea150c32f3.
2024-11-13 10:21:55 -06:00
Ben Meadors
ea150c32f3 Decrease max nodes for NRF52 to 80 as workaround to prevent FS blowouts (#5338)
* Decrease max nodes for NRF52 to 80 as workaround to prevent FS blowouts

* Don't redefine

* Newline
2024-11-13 07:43:05 -06:00
Ben Meadors
ac804818de Only allow 30 seconds minimum for power.on_battery_shutdown_after_secs (#5337) 2024-11-13 05:39:15 -06:00
Blake-Latchford
8fcfe7f28b Read voltage during init fixes #5276 (#5332)
Power::readPowerStatus is called on startup,
but AnalogBatteryLevel::getBattVoltage
skips the read because 5 seconds have not
elapsed since last_read_time_ms, which
is initialized to zero.

`batMv=3100` is reported because
AnalogBatteryLevel::last_read_value is
initialized as:
```
float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS);
```
2024-11-13 04:13:55 -06:00
GUVWAF
e866734a25 Handle repeated packet after potentially canceling previous Tx (#5330)
* Revert "Fix sending duplicate packets to PhoneAPI/MQTT (#5315)"

This reverts commit 40bc04b521.

* Handle repeated packet after potentially canceling previous Tx
2024-11-12 15:23:32 -06:00
Matthijs De Smedt
2ec3958cd8 Add support for ignoring nodes with is_ignored field in NodeInfo (#5319)
* Add support for is_ignored bool in NodeInfo

* is_ignored is not a boring node either

* Clean out metrics and position

* Clear the key too

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-12 13:27:44 -06:00
GUVWAF
f4b0e19a65 Fix another heap leak (#5328) 2024-11-12 10:59:29 -06:00
Ben Meadors
a49f080bd2 Revert "Portduino packaging: Move meshtastic/web out of /usr/share/doc (#5323)" (#5325)
This reverts commit 762ccdc1b9.
2024-11-12 06:40:46 -06:00
Ben Meadors
e65a754430 Remove board level extra from wismesh tap 2024-11-12 06:20:42 -06:00
Ben Meadors
a84324c4fa Don't attempt to save NodeDB on low-batt shutdown to prevent FS corruption (#5312) 2024-11-12 06:17:26 -06:00
Daniel.Cao
ff33a27789 Reduce the flash usage of wismeshtap platform (#5322)
* Reduce the flash usage of wismeshtap platform

* fix STOREFORWARD twice

* Reduce the flash usage of wismeshtap platform

* fix STOREFORWARD twice

* add range test

* Update platformio.ini

remove
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
-DMESHTASTIC_EXCLUDE_AUDIO=1

* Update platformio.ini

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-12 06:16:40 -06:00
Ben Meadors
51ea7ac627 Trunk toolchain versions 2024-11-12 06:12:09 -06:00
Ben Meadors
606c2e8eb0 Exclude paxcounter 2024-11-12 05:50:30 -06:00
Austin
762ccdc1b9 Portduino packaging: Move meshtastic/web out of /usr/share/doc (#5323)
* Portduino: Move meshtastic/web out of `doc`

* Remove /usr/share/doc/meshtasticd before linking
2024-11-12 16:14:12 +08:00
Michael Gjelsø
0acccdfe2d Don't send to public channel (#5310)
* Don't send to public channel

`p->to` wasn't set and had the same value as broadcast, it's now set to our own NodeNum.

* Trunk

* Update DetectionSensorModule.cpp

Take 3

* Revert NodeNum()
2024-11-11 19:11:54 -06:00
github-actions[bot]
0e4f7003c7 [create-pull-request] automated change (#5320)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-11 18:55:02 -06:00
GUVWAF
40bc04b521 Fix sending duplicate packets to PhoneAPI/MQTT (#5315)
* Fix potential duplicate packets to PhoneAPI/MQTT

* Fix include error for STM32

* Fix cppcheck error
2024-11-12 07:54:05 +08:00
Thomas Göttgens
eb8d38a7e9 radiolib update (#5246)
* update radiolib to 7.1.0
* stay at 7.0.2 for STM32, also remove unused board from ESP32 arch
---------
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-11 16:05:48 +01:00
Ben Meadors
3d5eb34c5c Add back some details to the PhoneAPI logs (#5313) 2024-11-11 07:01:29 -06:00
Ben Meadors
3a9a4bbb92 Coerce minimum neighborinfo interval on startup (#5314) 2024-11-11 07:00:56 -06:00
Daniel.Cao
6eba2789d0 rak10701 (rak wismeshtap) optimization (#5280)
* Improve the processing speed of virtual keyboards
* Remove the disable GPS feature, as it would interfere with the normal use of TFT
* Changed the default screen sleep time to 30s
* Rename platform rak10701 -> rak wismeshtap
* Fixed rak wismeshtap turned off gps caused the screen not to display
* Reduce the size of the flash, otherwise uf2 will not work

Co-authored-by: Daniel Cao <daniel.cao@rakwireless.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Tom Fifield <tom@tomfifield.net>
2024-11-11 13:37:43 +01:00
GUVWAF
9b4c260a92 Fix memory leak in MQTT (#5311) 2024-11-11 13:22:22 +01:00
Ben Meadors
667b4ef0f2 Exclude some niche modules by default and populate exclude_modules (#5300)
* Exclude some niche modules by default

* Start of intelligently excluding modules

---------

Co-authored-by: Tom Fifield <tom@tomfifield.net>
2024-11-10 13:36:49 -06:00
Tom Fifield
db76561930 Package file move - include dotfiles (#5303)
Adds shopt -s dotglob nullglob to ensure we get 'hidden' files in
our move command.
2024-11-10 20:56:44 +08:00
Tom Fifield
7bad070891 Fix syntax error with package builds (#5302)
test (]) and its parameters need a space between them.
2024-11-10 06:13:58 -06:00
Tom Fifield
6365fcfdc6 Update dependency versions (#5299)
Using platformio pkg outdated, discover that some versions are not
up-to-date. Update all apart from RadioLib (existing pull) and
SensorLib (doesn't compile).

Also, trunk formatted platformio.ini

Package                   Current    Wanted     Latest     Type     Environments
------------------------  ---------  ---------  ---------  -------  --------------------------
Adafruit BME280 Library   2.2.2      2.2.2      2.2.4      Library  tracker-t1000-e
Adafruit INA260 Library   1.5.0      1.5.0      1.5.2      Library  tracker-t1000-e
Adafruit LPS2X            2.0.4      2.0.4      2.0.6      Library  tracker-t1000-e
Adafruit LSM6DS           4.7.2      4.7.2      4.7.3      Library  tracker-t1000-e
Adafruit MCP9808 Library  2.0.0      2.0.0      2.0.2      Library  tracker-t1000-e
Adafruit MPU6050          2.2.4      2.2.4      2.2.6      Library  tracker-t1000-e
Adafruit SHT4x Library    1.0.4      1.0.4      1.0.5      Library  tracker-t1000-e
Adafruit Unified Sensor   1.1.11     1.1.11     1.1.14     Library  tracker-t1000-e
BME68x Sensor library     1.1.40407  1.1.40407  1.2.40408  Library  tracker-t1000-e
QMC5883LCompass           1.2.0      1.2.0      1.2.3      Library  tracker-t1000-e
RadioLib                  7.0.2      7.0.2      7.1.0      Library  wio-sdk-wm1110
SensorLib                 0.2.0      0.2.0      0.2.2      Library  tbeam
2024-11-10 06:13:31 -06:00
Tom Fifield
ab2cbada75 Web now(?) comes in a /build subdirector in the tar (#5301)
* Web now(?) comes in a /build subdirector in the tar

So let's move everything to where it's expected and cleanup before
trying to unzip.

* Add checks to avoid running unneeded commands

stops this failing in the event the build subdir goes away.
2024-11-10 19:58:06 +08:00
Jonathan Bennett
875b8641d3 Pin library versions in platform.io (#5293)
* Pin library versions in platform.io

This has been a constant source of headache. This moves to only updating libraries manually. Will eliminate the random build failures, and make rebuilding specific release versions possible.

* Bump ina219 to latest library version

* More lib version bumps
2024-11-09 16:06:17 -06:00
Jonathan Bennett
67c2c516a0 Use sudo for building armv7 2024-11-09 12:44:06 -06:00
Tom Fifield
623203ca3b Remove scary warning about full NodeDB (#5292)
NodeDB becoming full at 100 entries and cycling out old entries is normal behaviour. The user doesn't need to take any action and shouldn't be concerned when this happens.

Remove the warning from the screen and reduce loglevel to info.
2024-11-09 07:30:04 -06:00
github-actions[bot]
f28f0a9d90 [create-pull-request] automated change (#5290)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-09 05:31:09 -06:00
GUVWAF
893efe4f11 Always set the channel corresponding to a node (#5287) 2024-11-09 11:30:12 +08:00
GUVWAF
2c2213ef9b Add setting to transmit NeighborInfo over LoRa (#5286)
* Add setting to transmit NeighborInfo over LoRa
Only if not using the default channel

* Bump minimum broadcast interval for NeighborInfo to 4 hours
2024-11-09 09:38:48 +08:00
github-actions[bot]
439c1dec08 [create-pull-request] automated change (#5284)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-08 07:53:55 -06:00
Tavis
aa184e6d8b copy the has_relative_humidity value to telem packet from AHTX0 packet (#5277)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-08 07:59:36 +08:00
Marco Veneziano
2eea412f1c Fixed compile error when using GPS_DEBUG (#5275) 2024-11-07 16:19:31 -06:00
Thomas Göttgens
b0a5a26f58 fix wio-tracker-dev sensor scan (#5274) 2024-11-07 18:01:58 +01:00
Thomas Göttgens
a815a770b4 Sync up ESP32 build variants 2024-11-07 15:03:05 +01:00
Austin
286f3c6458 uClibc compatibility (#5270)
* uclibc compatibility

Adds compatibility with uclibc, the officially supported toolchain of the luckfox pico

* Explicitly link stdc++fs for std::filesystem

Bringing this over from buildroot-meshtastic
2024-11-07 14:23:08 +01:00
github-actions[bot]
b506f6dcb0 [create-pull-request] automated change (#5272)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-07 07:17:23 -06:00
Jeremiah K
bd3755bb33 Fix device flashing scripts so they work with esptool when it's installed via pipx (#5269)
* Try esptool.py in device flashing scripts for pipx compatibility

* esptool detection fixes in device flashing .bat's
2024-11-07 09:43:34 +08:00
Ben Meadors
73e2e25eb1 Smarter traffic scaling (#5264) 2024-11-06 15:00:53 -06:00
GUVWAF
3bd3911913 Only PKC encrypt when packet originates from us (#5267) 2024-11-06 22:00:26 +01:00
Ben Meadors
982190936d More log reductions. I'll probably stop now ;-) (#5263) 2024-11-06 21:03:25 +08:00
Ben Meadors
8498b175e7 Add exception for RTC to not strip time from position (#5262)
* Add exception for RTC to not strip time from position

* t
2024-11-06 10:06:43 +08:00
github-actions[bot]
255713d23d [create-pull-request] automated change (#5258)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-05 19:33:20 -06:00
Timo
8e2a3e5728 fix display of umlauts (UTF-8 left byte C3) (#5252) 2024-11-05 04:36:37 -06:00
Ben Meadors
f769c50fa5 More reduction (#5256)
* Now with even fewer ings

* Ye

* Mo

* QMA6100PSensor
2024-11-04 19:15:59 -06:00
GUVWAF
7ba6d97e99 Release no-LoRa packet after sending to phone (#5254) 2024-11-04 14:13:54 -06:00
GUVWAF
f3b698905d Disable automatic NodeInfo request when NodeDB is full (#5255) 2024-11-04 14:06:12 -06:00
Ben Meadors
50dac38a1b Pass#2: Lots more savings in logs and string reduction surgery (#5251)
* Pass#2: Lots more savings in logs and string reduction surgery

* Don't need Thread suffix either

* Warn
2024-11-04 12:16:25 -06:00
Jonathan Bennett
bf944e78d8 More configs (#5253)
* Add config.available for the MeshAdv 900M30S

* Move configs out of config.yaml
2024-11-04 11:17:32 -06:00
Tom Fifield
e71be778dd Fix cppcheck HIGH error (#5250)
https://github.com/meshtastic/firmware/pull/5247 introduced new
protobufs, particularly the excluded_modules feature.

Immediately afterward, cppcheck started sounding klaxons about
an unitialized variable. This patch simply sets excluded_modules
to none as a temporary measure while the feature from protobuf
is integrated into code.
2024-11-04 07:03:50 -06:00
Tom Fifield
276067065e Log cleanups (#5135)
* Log cleanups

change log levels, shorten log messages, delete commented out logs

* Address comments from review

* Remove full stops

* EDEBUG --> DEBUG
2024-11-04 06:09:23 -06:00
github-actions[bot]
a628c93125 [create-pull-request] automated change (#5247)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-04 05:40:55 -06:00
Ben Meadors
03aaaafa13 Exclude preferred routing roles from nodeinfo interrogation behavior (#5242)
* Exclude prefered routing roles from nodeinfo interrogation behavior

* Exclude prefered routing roles from nodeinfo interrogation behavior

* Update MeshService.cpp

* Rework logic to prevent spammy router logs
2024-11-04 19:05:03 +08:00
Thomas Göttgens
0a82fd28b3 PIO_ENV (#5239)
* add hw_env to packet

needs https://github.com/meshtastic/protobufs/pull/616

* rename to pio_env

* Move to mynodeinfo

* Includy doody

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-03 20:02:13 -06:00
github-actions[bot]
89c186e662 [create-pull-request] automated change (#5243)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-03 19:48:50 -06:00
github-actions[bot]
8c99f913c1 [create-pull-request] automated change (#5241)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-03 16:18:38 -06:00
Thomas Göttgens
d00acc5d7b Update stale_bot.yml 2024-11-03 20:10:17 +01:00
Austin
9415254dda musl compatibility (#5219)
* musl compat

* trunk fmt

* Update platform-native, including musl fix

https://github.com/meshtastic/platform-native/pull/5

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-03 14:24:04 +01:00
Tom Fifield
448c754882 LR1110 - remove old comment referring to non-existent function. (#5233)
It seems like there was no setrxgain function in RadioLib. Since
we're unlikely to uncomment and enable this non-existent feature,
remove this code.
2024-11-03 14:14:06 +01:00
GUVWAF
da7424a604 Improve ACK logic for responses and repeated packets (#5232)
* Don't send ACKs to responses over multiple hops

* Move repeated sending logic to `wasSeenRecently()`

* Add exception for simulator for duplicate packets from PhoneAPI

* Add short debug message
2024-11-03 06:21:45 -06:00
Tom Fifield
1bec23b6bb Fix displays showing "GPS Not Present" until first lock (#5229)
https://github.com/meshtastic/firmware/pull/5160 introduced a change
which made first publication of GPS information take up to 15mins.
For that initial period, displays would show "No GPS Present", even
if one was detected.

This change fixes that bug, triggering publication immediately after
a GPS module is detected.
2024-11-03 06:19:15 -06:00
Technologyman00
bee474ee54 Spell check all Code (#5228)
* Spelling Fixes

* More Spelling Errors

* More Spelling Checks

* fixed wording

* Undo mesh\generated changes

* Missed one file on readd

* missed second file
2024-11-03 09:25:05 +08:00
github-actions[bot]
93bc61c855 [create-pull-request] automated change (#5227)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-02 16:30:43 +01:00
Ben Meadors
0fc5c9b0d7 Create CODE_OF_CONDUCT.md (#5225) 2024-11-02 07:57:33 -05:00
Tom Fifield
b0c924f185 Optimise GPS Baud Rate cycle (#5102)
* Optimise GPS Baud Rate cycle

Previously, our baud rate cycled through one list twice.

There were some rarer baudrates in there, so this code
separates out those into a dedicated list that is only
run through if detection fails for common bauds. We also
only run through each baud rate once.

* Fix first time around bug

Would have always reset GPS baudrate every time.

* Add support for fixing GPS_BAUDRATE

If GPS_BAUDRATE is set in variant.h, the deployer knows something we
don't about the GPS. Used especially when the GPS is soldered to a board
in a commercial product :) If we see that, we don't try other baud rates
at all.

* Don't print blank lines in GPS_DEBUG.

* Try GPS_BAUDRATE first, not only.

* Fix spelling mistakes in comments

* Only use GPS_BAUDRATE if specified in variant.h

* Modify RareSerial Speeds based on FIXED or not.
2024-11-02 07:51:12 -05:00
github-actions[bot]
8801bc5ce9 [create-pull-request] automated change (#5223)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-11-02 05:58:06 -05:00
Jonathan Bennett
cf476eb87c Remove assert in mesh-pb-constants.cpp (#5207)
* Remove assert in mesh-pb-constants.cpp

* Add raw packet output to portduino trace logging.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-02 05:38:44 -05:00
todd-herbert
ba2f25293b Fix flipped logic after move to Throttle::isWithinTimespanMs (#5221) 2024-11-02 05:36:40 -05:00
GUVWAF
2d4d36c605 Drop oldest packet from radio when queue is full (#5212)
And still notify Router

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-11-01 15:48:55 -05:00
Ben Meadors
cbe74009a9 Comment out unused var to get rid of warning 2024-11-01 15:46:11 -05:00
Ben Meadors
701421b50a Trunk fmt 2024-11-01 15:17:25 -05:00
Aaron.Lee
336cdc0efe Add Heltec V3 battery read pin detect function (#5196) 2024-11-01 15:12:41 -05:00
Ben Meadors
a1ac358b0a Don't try to count non-lora transmissions into airtime (or attempt to decode) (#5215)
* Don't try to count non-lora transmissions into airtime (or attempt to decode)

* Don't need to check utilization anymore
2024-11-01 13:20:11 -05:00
dependabot[bot]
8462d65f76 Bump actions/github-script from 5 to 7 in /.github/workflows (#5214)
Bumps [actions/github-script](https://github.com/actions/github-script) from 5 to 7.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v5...v7)

---
updated-dependencies:
- dependency-name: actions/github-script
  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-11-01 07:50:40 -05:00
Ben Meadors
10dd8af614 Eh? 2024-11-01 06:10:42 -05:00
Ben Meadors
9c06c492d9 Use one from the other PR 2024-11-01 06:04:14 -05:00
Ben Meadors
7e3c369e87 Trunk fmt on comment 2024-11-01 05:58:48 -05:00
Ben Meadors
732cf4832a Bump version since I killed the PR 2024-11-01 05:20:00 -05:00
Jonathan Bennett
545ebf9b17 Don't skip GPS serial speeds, and always land on GPS_BAUDRATE (#5195)
* Don't skip GPS serial speeds, and always land on GPS_BAUDRATE

* Update log message to match.

* print the value instead
2024-11-01 08:44:02 +08:00
Ben Meadors
7912c214c7 Increase NimBLE stack size (#5202) 2024-10-31 15:09:27 -05:00
Alexander Begoon
600208ab0b Refactor getMacAddr function to retrieve MAC address as MAC-48 for IEEE 802.15.4 compatibility (#5208) 2024-10-31 15:07:59 -05:00
GUVWAF
462a0718cf Fix SerialModule getting packet from ourselves (#5206) 2024-10-31 11:46:00 -05:00
Thomas Göttgens
aae346aef7 Update stale_bot.yml 2024-10-30 23:02:59 +01:00
Andre K
28b469dbf0 fix: don't broadcast public keys if the user is licensed (#5190)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2024-10-30 12:05:09 -05:00
Ben Meadors
5f6e19d971 As a Router 2024-10-30 06:02:59 -05:00
Thomas Göttgens
0726eaa678 Update stale_bot.yml 2024-10-30 10:43:08 +01:00
Thomas Göttgens
50fb575caa Update stale_bot.yml 2024-10-30 10:16:40 +01:00
Thomas Göttgens
cc59a50cba Test: mark issues as stale 2024-10-30 10:14:59 +01:00
Jonathan Bennett
b3ba23b4e8 Don't generate or populate PKC keys in licensed mode 2024-10-29 14:17:14 -05:00
Ben Meadors
936260fca3 Default rebroadcast mode for Router and Repeater to ignore problematic portnums (#5178)
* Default rebroadcast mode for Router and Repeater to ignore problematic portnums

* Verbiage

* IS_ONE_OF
2024-10-29 05:44:32 -05:00
Tom Fifield
2945b9cfbe De-duplicate Ambient LED management code (#5156)
We currently have 4 different places where we have the logic for
modifying LED state of the various types of Ambient LEDs,
ExternalNotificationModule::SetExternalOff
ExternalNotificationModule::SetExternalOn
AmbientLightingThread::setLighting
AmbientLightingThread::setLightingOff

This patch de-duplicates the methods in ExternalNotification to
a single method, using a boolean to toggle whether we're turning
things on or off.
2024-10-29 05:41:21 -05:00
Megaceryle-alcyon
ed03d28a83 Added PA1616S GPS module (#5157)
* Added GPS chip PA1616S

GPS chip PA1616S is used in some recent Adafruit GPS breakout boards.

* Update GPS.cpp

---------

Co-authored-by: picusviridis <mesh.culprit381@passmail.net>
2024-10-29 09:34:01 +01:00
Jonathan Bennett
850f61d2d0 Native config.d (#5165)
* Add support for loading yaml from a config directory

* Add waveshare hats to the new config.d approach

* Move to available.d for module inactive module configs
2024-10-28 21:48:10 -05:00
Ben Meadors
e12fd27b49 Trunkdor the burninator 2024-10-28 06:40:48 -05:00
Spiffysec
77dfc92f1e Update GPSUpdateScheduling.cpp (#5160)
* Update GPSUpdateScheduling.cpp

Default value is too short, resulting in unstable GPS locks on T1000-E (possibly others). Fix has been tested an confirmed working with no adverse effects, by multiple users. Also discussed at length on Discord

* Coerce minimum instead of hardcode

* config

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-10-28 06:18:03 -05:00
github-actions[bot]
c4eb9a6d7f [create-pull-request] automated change (#5176)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-10-28 06:16:06 -05:00
Tom Fifield
195f109ef7 Cherrry pick bin/config-dist.yml from TFT-GUI-Work (#5168)
* support SHCHV 3.5 RPi TFT+Touchscreen

* add TZT 2.0inch ST7789 config

---------

Co-authored-by: mverch67 <manuel.verch@gmx.de>
2024-10-28 09:31:21 +01:00
Tom Fifield
3c8ca39eff cherry-pick: fix nrf builds (#5172)
* fix nrf builds

* fix rp2040 + monteops build

* Bump lovyan version

---------

Co-authored-by: mverch67 <manuel.verch@gmx.de>
2024-10-28 09:30:39 +01:00
Tom Fifield
c071eed6a3 cherry-pick: unphone support (#5174)
* unphone part 1

* Unphone support

* update HWid unphone

---------

Co-authored-by: mverch67 <manuel.verch@gmx.de>
2024-10-28 09:25:25 +01:00
Tom Fifield
d14d42ba2c diy mesh-tab initial files (#5169)
Co-authored-by: mverch67 <manuel.verch@gmx.de>
2024-10-28 09:23:49 +01:00
Jonathan Bennett
82145e0661 Cherry picks (#5166)
* fix compiler error std::find()

* fix wifi/bt connection status

* try-fix crash

* added 1200baud reset

---------

Co-authored-by: mverch67 <manuel.verch@gmx.de>
2024-10-28 10:21:57 +10:00
Ben Meadors
1334d07c6a Trunk updates 2024-10-27 06:57:11 -05:00
Muhammad Shah
bf760a44ba Icarus - Fix platform dependency version and add selection button (#5161)
* Update variant.h

* Update platformio.ini
2024-10-27 05:51:51 -05:00
mverch67
94ff67e927 fix spiLock in RadioLibInterface 2024-10-27 10:55:23 +01:00
Muhammad Shah
e37369a25f Icarus - Custom PCB (#5155)
* added Icarus

* added Icarus

* Update platformio.ini

* Fixed I2C ports

* Update variant.h
2024-10-26 19:24:30 -05:00
mverch67
a8bd1ee0da stability: add SPI lock before saving via littleFS 2024-10-26 16:01:46 +02:00
github-actions[bot]
2568d4fcd8 [create-pull-request] automated change (#5153)
Co-authored-by: caveman99 <25002+caveman99@users.noreply.github.com>
2024-10-26 15:51:28 +02:00
Thomas Göttgens
adf1bc4b0e fix tracker build (#5151)
fix tracker 1000 build
2024-10-26 14:40:10 +02:00
github-actions[bot]
ea63f035d1 [create-pull-request] automated change (#5137)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-10-26 12:07:07 +02:00
Tom Fifield
e394bc6f8f De-duplicate log-level determination (#5148)
RedirectablePrint had a method, getLogLevel, which did exactly
what code in SerialConsole did. Let's use that method rather than
duplicating the code.
2024-10-26 12:06:50 +02:00
Tom Fifield
a0e468b16e Remove unused AXP debug code (#5149)
This was shuffled around a couple years ago, but hasn't been used
since, and we had two copies in the code. Delete it.
2024-10-26 12:04:46 +02:00
Thomas Göttgens
93318b4f56 T1000-E Peripherals (#5141)
* T1000-E Peripherals
- enable intelligent charge controller signals
- enable Accelerometer
- enable internal I2C bus
- provide Power to Accelerometer

* POC Accelerometer Code (wakeScreen is moot for that device, just test if the driver works)
* fix building without the sensor
2024-10-26 12:03:28 +02:00
Mark Trevor Birss
0c0da3909f Update variant.h (#5140) 2024-10-25 08:07:01 +10:00
Manuel
701293c2d3 fix missing includes (#5138) 2024-10-24 21:58:24 +02:00
github-actions[bot]
6485f037ec [create-pull-request] automated change (#5133)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-10-23 21:21:49 -05:00
Ben Meadors
ca5f71f774 Add device unique id (#5092)
* Add device unique id

* Trunk

* WIP

* Esp32 implementation

* Trunk

* Check for ESP_EFUSE_OPTIONAL_UNIQUE_ID

* Comment print

* Trunk
2024-10-23 21:18:37 -05:00
panaceya
57667f1028 ADD: Configurable UPLINK_ENABLED and DOWNLINK_ENABLED in userPrefs.h (#5120) 2024-10-23 05:26:44 -05:00
Craig Bailey
3f1c86f953 Update meshtasticd.service (#5118)
Adding restart on service failure with 3 seconds between restart to stop fasst restart loops. Adding StartLimitBurst to limit it to 5 restarts in 200 seconds.
2024-10-22 16:22:10 -05:00
github-actions[bot]
4416ac57cf [create-pull-request] automated change (#5124)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-10-21 16:06:56 -05:00
Robert
a4705d2c19 add RFC 3927 IP address space to private IP checks (#5115)
Add the RFC 3927 IP address block (169.254.0.0/16), also referred to as IPIPA, to the private address checks for MQTT functionality.
2024-10-21 19:25:27 +11:00
aussieklutz
5ff8c904c8 MPR121 Touch IC Based Keypad Input Module (#5103)
Implements an input driver utilising the MPR121 Touch IC and is compatible with common MPR121 keypad PCB's.

- Implements a "candybar" phone style 12-key keypad
  - multiple taps to rotate through the character set
  - longpress for navigation keys
  - keymap to allow arbitrary routing of MPR121 pin to button configuration
  - extendable to other key functions
- Integrates with the existing kbI2cBase implementation
- Works with CannedMessageModule Freetext mode
- Can be used with common MPR121 boards, such as https://www.amazon.com/MPR121-Capacitive-Keyboard-Buttons-Sensitive/dp/B083R89CHB/ref=sr_1_6
- Of use for PCB based radios, where some form of low surface area low component freetext input is required, but also without consuming too many IO pins.
- Tested on a T3S3 connected to Wire1 (Second) interface.
  - Demonstration of functionality: https://youtu.be/UI6QP6nGvhY
2024-10-21 17:53:36 +11:00
GUVWAF
09c8642aa6 Fix rebroadcasting encrypted packets when KNOWN_ONLY or LOCAL_ONLY is used (#5109) 2024-10-20 17:04:45 -05:00
Thomas Göttgens
82bcd503a3 Merge pull request #5112 from meshtastic/preamble-length
Wide_Lora uses 12 symbols to be compatible with SX1280
2024-10-20 22:06:06 +02:00
Thomas Göttgens
18ca5b4449 Wide_Lora uses 12 symbols to be compatible with SX1280 2024-10-20 21:54:07 +02:00
Tom Fifield
2ba72c154a Fix GPS_DEBUG output (#5100)
After the recent change to move logging line breaks to a central
location, GPS_DEBUG is now emitting one character per line,
making the logs unusable.

Patch uses local strings and appends to collate and then print
in the right places.

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

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-10-20 04:46:25 -05:00
Ben Meadors
7e3931b05d Move 115200 baud GNSS probe earlier (#5101)
* Move 115200 baud GNSS probe earlier

* Even more optimized!
2024-10-19 20:05:52 -05:00
Ben Meadors
4575352d8c Initial NODENUM_BROADCAST_NO_LORA implementation with NeighborInfo module (#5087)
* Initial NODENUM_BROADCAST_NO_LORA implementation with NeighborInfo module

* isBroadcast

* Trunkt
2024-10-19 12:48:00 -05:00
Thomas Göttgens
b1b6bce6b7 Merge pull request #5095 from meshtastic/revert-5036-caveman99-patch-1
Revert "Permanently engage !CTRL"
2024-10-19 19:06:33 +02:00
Thomas Göttgens
304f26b909 Revert "Permanently engage !CTRL" 2024-10-19 19:01:58 +02:00
madeofstown
a27f9fcdbd Add -p flag (#5093)
Add the `-p` to the `mkdir` so it doesn't fail when the folder already exists

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-10-18 20:19:24 -05:00
Jonathan Bennett
dfeb33d46e Add DIO2_AS_RF_SWITCH to pinedio prefilled config. 2024-10-18 12:30:46 -05:00
github-actions[bot]
b8b6894d58 [create-pull-request] automated change (#5091)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-10-18 06:00:55 -05:00
Technologyman00
934be69663 Add buzzer feedback on GPS toggle (#5090)
Triple Press on buttons toggles GPS enable/disable.

This enhancement plays a triple-beep so that users of devices with buzzers can get audible feedback about whether they have turned the GPS off or on. This is especially valuable for screenless devices such as the T1000E where it may not be immediately obvious the GPS has been disabled.
2024-10-18 14:40:18 +11:00
Ben Meadors
ec9e562a77 Coerce minimum telemetry interval of 30 minutes on defaults and make new default interval one hour (#5086)
* Coerce minimum telemetry interval of 30 minutes on defaults and make new default interval one hour

* Smaller log messages
2024-10-17 13:33:52 -05:00
Johnathon Mohr
fbb6778415 Account for port specification with IP address for MQTT server. Some additional format validation. (#5084) 2024-10-17 05:05:35 -05:00
github-actions[bot]
2ea2b47690 [create-pull-request] automated change (#5085)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-10-16 19:51:11 -05:00
244 changed files with 4162 additions and 1925 deletions

View File

@@ -51,6 +51,7 @@ runs:
file: build.tar
target: build.tar
token: ${{ inputs.github_token }}
version: tags/v2.5.3
- name: Unpack web ui
if: inputs.include-web-ui == 'true'

View File

@@ -7,6 +7,8 @@ on:
required: true
type: string
permissions: read-all
jobs:
build-esp32:
runs-on: ubuntu-latest
@@ -24,6 +26,7 @@ jobs:
./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.bin
ota-firmware-target: release/bleota.bin

View File

@@ -26,10 +26,12 @@ jobs:
./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
include-web-ui: true
arch: esp32c3

View File

@@ -33,4 +33,5 @@ jobs:
artifact-paths: |
release/*.bin
release/*.elf
include-web-ui: true
arch: esp32c6

View File

@@ -7,6 +7,8 @@ on:
required: true
type: string
permissions: read-all
jobs:
build-esp32-s3:
runs-on: ubuntu-latest
@@ -24,6 +26,7 @@ jobs:
./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-s3.bin
ota-firmware-target: release/bleota-s3.bin

View File

@@ -13,8 +13,8 @@ jobs:
- name: Install libbluetooth
shell: bash
run: |
apt-get update -y --fix-missing
apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
sudo apt-get update -y --fix-missing
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
- name: Checkout code
uses: actions/checkout@v4

View File

@@ -13,8 +13,8 @@ jobs:
- name: Install libbluetooth
shell: bash
run: |
apt-get update -y --fix-missing
apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
sudo apt-get update -y --fix-missing
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
- name: Checkout code
uses: actions/checkout@v4

View File

@@ -203,6 +203,7 @@ jobs:
./device-*.sh
./device-*.bat
./littlefs-*.bin
./littlefswebui-*.bin
./bleota*bin
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
@@ -245,7 +246,8 @@ jobs:
if: ${{ github.event_name == 'workflow_dispatch' }}
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
needs: [
needs:
[
gather-artifacts,
package-raspbian,
package-raspbian-armv7l,

View File

@@ -50,11 +50,18 @@ jobs:
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
mkdir -p .debpkg/etc/meshtasticd/config.d
mkdir -p .debpkg/etc/meshtasticd/available.d
mkdir -p .debpkg/usr/lib/systemd/system/
tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
shopt -s dotglob nullglob
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi
gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
cp release/meshtasticd_linux_x86_64 .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles

View File

@@ -50,11 +50,18 @@ jobs:
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
mkdir -p .debpkg/etc/meshtasticd/config.d
mkdir -p .debpkg/etc/meshtasticd/available.d
mkdir -p .debpkg/usr/lib/systemd/system/
tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
shopt -s dotglob nullglob
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi
gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles

View File

@@ -50,11 +50,18 @@ jobs:
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
mkdir -p .debpkg/etc/meshtasticd/config.d
mkdir -p .debpkg/etc/meshtasticd/available.d
mkdir -p .debpkg/usr/lib/systemd/system/
tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
shopt -s dotglob nullglob
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi
gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
cp release/meshtasticd_linux_armv7l .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles

22
.github/workflows/stale_bot.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: process stale Issues and PR's
on:
schedule:
- cron: 0 6 * * *
workflow_dispatch: {}
permissions:
issues: write
pull-requests: write
actions: write
jobs:
stale_issues:
name: Close Stale Issues
runs-on: ubuntu-latest
steps:
- name: Stale PR+Issues
uses: actions/stale@v9.0.0
with:
exempt-issue-labels: pinned,3.0
exempt-pr-labels: pinned,3.0

43
.github/workflows/trunk_format_pr.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Run Trunk Fmt on PR Comment
on:
issue_comment:
types: [created]
jobs:
trunk-fmt:
if: github.event.issue.pull_request != null && contains(github.event.comment.body, 'trunk fmt')
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install trunk
run: curl https://get.trunk.io -fsSL | bash
- name: Run Trunk Fmt
run: trunk fmt
- name: Commit and push changes
run: |
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
- name: Comment on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '`trunk fmt` has been run on this PR.'
})

View File

@@ -1,34 +1,34 @@
version: 0.1
cli:
version: 1.22.6
version: 1.22.8
plugins:
sources:
- id: trunk
ref: v1.6.3
ref: v1.6.4
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- trufflehog@3.82.6
- trufflehog@3.83.6
- yamllint@1.35.1
- bandit@1.7.10
- checkov@3.2.256
- terrascan@1.19.1
- trivy@0.55.2
- checkov@3.2.287
- terrascan@1.19.9
- trivy@0.56.2
#- trufflehog@3.63.2-rc0
- taplo@0.9.3
- ruff@0.6.8
- ruff@0.7.3
- isort@5.13.2
- markdownlint@0.42.0
- oxipng@9.1.2
- svgo@3.3.2
- actionlint@1.7.3
- actionlint@1.7.4
- flake8@7.1.1
- hadolint@2.12.0
- shfmt@3.6.0
- shellcheck@0.10.0
- black@24.8.0
- black@24.10.0
- git-diff-check
- gitleaks@8.20.0
- gitleaks@8.21.1
- clang-format@16.0.3
- prettier@3.3.3
ignore:

4
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,4 @@
# Contributor Covenant Code of Conduct
The Meshtastic Firmware project is subject to the code of conduct for the parent project, which can be found here:
https://meshtastic.org/docs/legal/conduct/

View File

@@ -31,7 +31,7 @@ build_flags =
-DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DSERIAL_BUFFER_SIZE=4096
-DLIBPAX_ARDUINO
@@ -43,6 +43,7 @@ lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.2
https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587

View File

@@ -23,6 +23,7 @@ lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
lewisxhe/XPowersLib@^0.2.6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
rweather/Crypto@^0.4.0

View File

@@ -14,13 +14,18 @@ build_flags =
-Wno-unused-variable
-Isrc/platform/nrf52
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
-DMESHTASTIC_EXCLUDE_AUDIO=1
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
-DMAX_NUM_NODES=80
build_src_filter =
${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}
${radiolib_base.lib_deps}
rweather/Crypto@^0.4.0
lib_ignore =
BluetoothOTA
BluetoothOTA
lvgl

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#6b3796d697481c8f6e3f4aa5c111bd9979f29e64
platform = https://github.com/meshtastic/platform-native.git#bcd02436cfca91f7d28ad0f7dab977c6aaa781af
framework = arduino
build_src_filter =
@@ -23,8 +23,9 @@ build_src_filter =
lib_deps =
${env.lib_deps}
${networking_base.lib_deps}
${radiolib_base.lib_deps}
rweather/Crypto@^0.4.0
lovyan03/LovyanGFX@^1.1.16
https://github.com/lovyan03/LovyanGFX.git#1401c28a47646fe00538d487adcb2eb3c72de805
build_flags =
${arduino_base.build_flags}
@@ -32,6 +33,7 @@ build_flags =
-Isrc/platform/portduino
-DRADIOLIB_EEPROM_UNSUPPORTED
-DPORTDUINO_LINUX_HARDWARE
-lstdc++fs
-lbluetooth
-lgpiod
-lyaml-cpp

View File

@@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets
[rp2040_base]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1
extends = arduino_base
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.0.3
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#996c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
@@ -22,4 +22,5 @@ lib_ignore =
lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
rweather/Crypto

View File

@@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets
[rp2350_base]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#9e55f6db5c56b9867c69fe473f388beea4546672
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1
extends = arduino_base
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#a6ab6e1f95bc1428d667d55ea7173c0744acc03c ; 4.0.2+
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#96c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
@@ -16,8 +16,10 @@ build_src_filter =
lib_ignore =
BluetoothOTA
lvgl
lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
rweather/Crypto

View File

@@ -30,8 +30,9 @@ upload_protocol = stlink
lib_deps =
${env.lib_deps}
charlesbaynham/OSFS@^1.2.3
jgromes/RadioLib@7.0.2
https://github.com/caveman99/Crypto.git#f61ae26a53f7a2d0ba5511625b8bf8eff3a35d5e
lib_ignore =
mathertel/OneButton@~2.6.1
mathertel/OneButton@2.6.1
Wire

33
bin/base64_to_hex.py Normal file
View File

@@ -0,0 +1,33 @@
import sys
import base64
def base64_to_hex_string(b64_string):
try:
# Decode the Base64 string to raw bytes
decoded_bytes = base64.b64decode(b64_string)
except Exception as e:
raise ValueError(f"Invalid Base64 input: {e}")
# Check if the decoded result is exactly 32 bytes
if len(decoded_bytes) != 32:
raise ValueError("Decoded Base64 input must be exactly 32 bytes.")
# Convert each byte to its hex representation
hex_values = [f"0x{byte:02x}" for byte in decoded_bytes]
# Join the formatted hex values with commas
formatted_output = "{ " + ", ".join(hex_values) + " };"
return formatted_output
if __name__ == "__main__":
# Check if a Base64 string was provided in command line arguments
if len(sys.argv) != 2:
print("Usage: python script.py <base64-string>")
sys.exit(1)
b64_string = sys.argv[1]
try:
formatted_hex = base64_to_hex_string(b64_string)
print(formatted_hex)
except ValueError as e:
print(e)

View File

@@ -35,6 +35,11 @@ cp $SRCBIN $OUTDIR/$basename-update.bin
echo "Building Filesystem for ESP32 targets"
pio run --environment $1 -t buildfs
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$VERSION.bin
# Remove webserver files from the filesystem and rebuild
ls -l data/static # Diagnostic list of files
rm -rf data/static
pio run --environment $1 -t buildfs
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

View File

@@ -27,5 +27,4 @@ rm -r $OUTDIR/* || true
platformio pkg update --environment native || platformioFailed
pio run --environment native || platformioFailed
cp .pio/build/native/program "$OUTDIR/meshtasticd_linux_$(uname -m)"
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR
cp bin/native-install.* $OUTDIR

View File

@@ -1,15 +1,11 @@
### Many device configs have been moved to /etc/meshtasticd/available.d
### To activate, simply copy or link the appropriate file into /etc/meshtasticd/config.d
### Define your devices here using Broadcom pin numbering
### Uncomment the block that corresponds to your hardware
### Including the "Module:" line!
---
Lora:
# Module: sx1262 # Waveshare SX126X XXXM
# DIO2_AS_RF_SWITCH: true
# CS: 21
# IRQ: 16
# Busy: 20
# Reset: 18
# SX126X_ANT_SW: 6
# Module: sx1262 # Waveshare SX1302 LISTEN ONLY AT THIS TIME!
# CS: 7
@@ -20,6 +16,7 @@ Lora:
# CS: 0
# IRQ: 10
# Busy: 11
# DIO2_AS_RF_SWITCH: true
# spidev: spidev0.1
# Module: RF95 # Adafruit RFM9x
@@ -84,17 +81,6 @@ I2C:
Display:
### Waveshare 2.8inch RPi LCD
# Panel: ST7789
# CS: 8
# DC: 22 # Data/Command pin
# Backlight: 18
# Width: 240
# Height: 320
# Reset: 27
# Rotate: true
# Invert: true
### Waveshare 1.44inch LCD HAT
# Panel: ST7735S
# CS: 8 #Chip Select
@@ -114,6 +100,29 @@ Display:
# Height: 320
# Rotate: true
### SHCHV 3.5 RPi TFT+Touchscreen
# Panel: ILI9486
# spidev: spidev0.0
# BusFrequency: 30000000
# DC: 24
# Reset: 25
# Width: 320
# Height: 480
# OffsetRotate: 2
### TZT 2.0 Inch TFT Display ST7789V 240RGBx320
# Panel: ST7789
# spidev: spidev0.0
# # CS: 8 # can be freely chosen
# BusFrequency: 80000000
# DC: 24 # can be freely chosen
# Width: 320
# Height: 240
# Reset: 25 # can be freely chosen
# Rotate: true
# OffsetRotate: 1
# Invert: true
### You can also specify the spi device for the display to use
# spidev: spidev0.0
@@ -128,10 +137,6 @@ Touchscreen:
# IRQ: 24
# I2CAddr: 0x38
# Module: XPT2046 # Waveshare 2.8inch
# CS: 7
# IRQ: 17
### You can also specify the spi device for the touchscreen to use
# spidev: spidev0.0
@@ -154,4 +159,5 @@ Webserver:
General:
MaxNodes: 200
MaxMessageQueue: 100
MaxMessageQueue: 100
ConfigDirectory: /etc/meshtasticd/config.d/

View File

@@ -0,0 +1,18 @@
Display:
### Waveshare 2.8inch RPi LCD
Panel: ST7789
CS: 8
DC: 22 # Data/Command pin
Backlight: 18
Width: 240
Height: 320
Reset: 27
Rotate: true
Invert: true
Touchscreen:
### Note, at least for now, the touchscreen must have a CS pin defined, even if you let Linux manage the CS switching.
Module: XPT2046 # Waveshare 2.8inch
CS: 7
IRQ: 17

View File

@@ -0,0 +1,9 @@
Lora:
Module: sx1262
CS: 21
IRQ: 16
Busy: 20
Reset: 18
TXen: 13
RXen: 12
DIO3_TCXO_VOLTAGE: true

View File

@@ -0,0 +1,8 @@
Lora:
Module: sx1262 # Waveshare SX126X XXXM
DIO2_AS_RF_SWITCH: true
CS: 21
IRQ: 16
Busy: 20
Reset: 18
SX126X_ANT_SW: 6

View File

@@ -1,16 +1,26 @@
@ECHO OFF
set PYTHON=python
set WEB_APP=0
:: Determine the correct esptool command to use
where esptool >nul 2>&1
if %ERRORLEVEL% EQU 0 (
set "ESPTOOL_CMD=esptool"
) else (
set "ESPTOOL_CMD=%PYTHON% -m esptool"
)
goto GETOPTS
:HELP
echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME]
echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME] [--web]
echo Flash image file to device, but first erasing and writing system information
echo.
echo -h Display this help and exit
echo -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
echo -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: %PYTHON%)
echo -f FILENAME The .bin file to flash. Custom to your device type and region.
echo --web Flash WEB APP.
goto EOF
:GETOPTS
@@ -19,37 +29,44 @@ if /I "%1"=="--help" goto HELP
if /I "%1"=="-F" set "FILENAME=%2" & SHIFT
if /I "%1"=="-p" set ESPTOOL_PORT=%2 & SHIFT
if /I "%1"=="-P" set PYTHON=%2 & SHIFT
if /I "%1"=="--web" set WEB_APP=1 & SHIFT
SHIFT
IF NOT "__%1__"=="____" goto GETOPTS
IF "__%FILENAME%__" == "____" (
echo "Missing FILENAME"
goto HELP
goto HELP
)
IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
%PYTHON% -m esptool --baud 115200 erase_flash
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
%ESPTOOL_CMD% --baud 115200 erase_flash
%ESPTOOL_CMD% --baud 115200 write_flash 0x00 %FILENAME%
@REM Account for S3 and C3 board's different OTA partition
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% IF x%FILENAME:t-deck=%==x%FILENAME% IF x%FILENAME:wireless-paper=%==x%FILENAME% IF x%FILENAME:wireless-tracker=%==x%FILENAME% IF x%FILENAME:station-g2=%==x%FILENAME% IF x%FILENAME:unphone=%==x%FILENAME% (
IF x%FILENAME:esp32c3=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
%ESPTOOL_CMD% --baud 115200 write_flash 0x260000 bleota.bin
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-c3.bin
%ESPTOOL_CMD% --baud 115200 write_flash 0x260000 bleota-c3.bin
)
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
) else (
%ESPTOOL_CMD% --baud 115200 write_flash 0x260000 bleota-s3.bin
)
for %%f in (littlefs-*.bin) do (
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
IF %WEB_APP%==1 (
for %%f in (littlefswebui-*.bin) do (
%ESPTOOL_CMD% --baud 115200 write_flash 0x300000 %%f
)
) else (
for %%f in (littlefs-*.bin) do (
%ESPTOOL_CMD% --baud 115200 write_flash 0x300000 %%f
)
)
) else (
echo "Invalid file: %FILENAME%"
goto HELP
goto HELP
) else (
echo "Invalid file: %FILENAME%"
goto HELP
goto HELP
)
:EOF

View File

@@ -1,22 +1,45 @@
#!/bin/sh
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
WEB_APP=false
# Determine the correct esptool command to use
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
ESPTOOL_CMD="$PYTHON -m esptool"
elif command -v esptool >/dev/null 2>&1; then
ESPTOOL_CMD="esptool"
elif command -v esptool.py >/dev/null 2>&1; then
ESPTOOL_CMD="esptool.py"
else
echo "Error: esptool not found"
exit 1
fi
set -e
# Usage info
show_help() {
cat <<EOF
Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME]
Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME] [--web]
Flash image file to device, but first erasing and writing system information"
-h Display this help and exit
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
-f FILENAME The .bin file to flash. Custom to your device type and region.
--web Flash WEB APP.
EOF
}
# Preprocess long options like --web
for arg in "$@"; do
case "$arg" in
--web)
WEB_APP=true
shift # Remove this argument from the list
;;
esac
done
while getopts ":hp:P:f:" opt; do
case "${opt}" in
@@ -49,19 +72,23 @@ shift "$((OPTIND - 1))"
if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
$ESPTOOL_CMD erase_flash
$ESPTOOL_CMD write_flash 0x00 ${FILENAME}
# Account for S3 board's different OTA partition
if [ -n "${FILENAME##*"s3"*}" ] && [ -n "${FILENAME##*"-v3"*}" ] && [ -n "${FILENAME##*"t-deck"*}" ] && [ -n "${FILENAME##*"wireless-paper"*}" ] && [ -n "${FILENAME##*"wireless-tracker"*}" ] && [ -n "${FILENAME##*"station-g2"*}" ] && [ -n "${FILENAME##*"unphone"*}" ]; then
if [ -n "${FILENAME##*"esp32c3"*}" ]; then
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
$ESPTOOL_CMD write_flash 0x260000 bleota.bin
else
"$PYTHON" -m esptool write_flash 0x260000 bleota-c3.bin
$ESPTOOL_CMD write_flash 0x260000 bleota-c3.bin
fi
else
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
$ESPTOOL_CMD write_flash 0x260000 bleota-s3.bin
fi
if [ "$WEB_APP" = true ]; then
$ESPTOOL_CMD write_flash 0x300000 littlefswebui-*.bin
else
$ESPTOOL_CMD write_flash 0x300000 littlefs-*.bin
fi
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
else
show_help

View File

@@ -2,6 +2,14 @@
set PYTHON=python
:: Determine the correct esptool command to use
where esptool >nul 2>&1
if %ERRORLEVEL% EQU 0 (
set "ESPTOOL_CMD=esptool"
) else (
set "ESPTOOL_CMD=%PYTHON% -m esptool"
)
goto GETOPTS
:HELP
echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME]
@@ -24,17 +32,17 @@ IF NOT "__%1__"=="____" goto GETOPTS
IF "__%FILENAME%__" == "____" (
echo "Missing FILENAME"
goto HELP
goto HELP
)
IF EXIST %FILENAME% IF NOT x%FILENAME:update=%==x%FILENAME% (
echo Trying to flash update %FILENAME%
%PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
%ESPTOOL_CMD% --baud 115200 write_flash 0x10000 %FILENAME%
) else (
echo "Invalid file: %FILENAME%"
goto HELP
goto HELP
) else (
echo "Invalid file: %FILENAME%"
goto HELP
goto HELP
)
:EOF

View File

@@ -2,6 +2,18 @@
PYTHON=${PYTHON:-$(which python3 python|head -n 1)}
# Determine the correct esptool command to use
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
ESPTOOL_CMD="$PYTHON -m esptool"
elif command -v esptool >/dev/null 2>&1; then
ESPTOOL_CMD="esptool"
elif command -v esptool.py >/dev/null 2>&1; then
ESPTOOL_CMD="esptool.py"
else
echo "Error: esptool not found"
exit 1
fi
# Usage info
show_help() {
cat << EOF
@@ -9,7 +21,7 @@ Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME]
Flash image file to device, leave existing system intact."
-h Display this help and exit
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
-f FILENAME The *update.bin file to flash. Custom to your device type.
@@ -30,7 +42,7 @@ while getopts ":hp:P:f:" opt; do
f) FILENAME=${OPTARG}
;;
*)
echo "Invalid flag."
echo "Invalid flag."
show_help >&2
exit 1
;;
@@ -45,7 +57,7 @@ shift "$((OPTIND-1))"
if [ -f "${FILENAME}" ] && [ -z "${FILENAME##*"update"*}" ]; then
printf "Trying to flash update ${FILENAME}"
$PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME}
$ESPTOOL_CMD --baud 115200 write_flash 0x10000 ${FILENAME}
else
show_help
echo "Invalid file: ${FILENAME}"

View File

@@ -1,12 +1,16 @@
[Unit]
Description=Meshtastic Native Daemon
After=network-online.target
StartLimitInterval=200
StartLimitBurst=5
[Service]
User=root
Group=root
Type=simple
ExecStart=/usr/sbin/meshtasticd
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
cp "release/meshtasticd_linux_$(uname -m)" /usr/sbin/meshtasticd
mkdir /etc/meshtasticd
mkdir -p /etc/meshtasticd
if [[ -f "/etc/meshtasticd/config.yaml" ]]; then
cp bin/config-dist.yaml /etc/meshtasticd/config-upgrade.yaml
else

View File

@@ -88,12 +88,13 @@ Import("projenv")
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
verObj = readProps(prefsLoc)
print("Using meshtastic platformio-custom.py, firmware version " + verObj["long"])
print("Using meshtastic platformio-custom.py, firmware version " + verObj["long"] + " on " + env.get("PIOENV"))
# General options that are passed to the C and C++ compilers
projenv.Append(
CCFLAGS=[
"-DAPP_VERSION=" + verObj["long"],
"-DAPP_VERSION_SHORT=" + verObj["short"],
"-DAPP_ENV=" + env.get("PIOENV"),
]
)

View File

@@ -28,6 +28,8 @@
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},

41
boards/icarus.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": "icarus"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "icarus",
"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://icarus.azlan.works",
"vendor": "Muhammad Shah"
}

46
boards/unphone.json Normal file
View File

@@ -0,0 +1,46 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi",
"partitions": "default_8MB.csv"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DUNPHONE_SPIN=9",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
["0x16D0", "0x1178"],
["0x303a", "0x1001"]
],
"mcu": "esp32s3",
"variant": "unphone"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "unPhone",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8323072,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://unphone.net/",
"vendor": "University of Sheffield"
}

View File

@@ -29,7 +29,7 @@ default_envs = tbeam
;default_envs = rak4631
;default_envs = rak4631_eth_gw
;default_envs = rak2560
;default_envs = rak10701
;default_envs = rak_wismeshtap
;default_envs = wio-e5
;default_envs = radiomaster_900_bandit_nano
;default_envs = radiomaster_900_bandit_micro
@@ -39,128 +39,126 @@ default_envs = tbeam
;default_envs = heltec_vision_master_e213
;default_envs = heltec_vision_master_e290
;default_envs = heltec_mesh_node_t114
extra_configs =
arch/*/*.ini
variants/*/platformio.ini
arch/*/*.ini
variants/*/platformio.ini
description = Meshtastic
[env]
test_build_src = true
extra_scripts = bin/platformio-custom.py
; note: we add src to our include search path so that lmic_project_config can override
; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile
; of code is a heap corruption bug!
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
; The Radiolib stuff will speed up building considerably. Exclud all the stuff we dont need.
build_flags = -Wno-missing-field-initializers
-Wno-format
-Isrc -Isrc/mesh -Isrc/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
-DUSE_THREAD_NAMES
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
-DPB_ENABLE_MALLOC=1
-DRADIOLIB_EXCLUDE_CC1101=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
-Wno-format
-Isrc -Isrc/mesh -Isrc/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
-DUSE_THREAD_NAMES
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
-DPB_ENABLE_MALLOC=1
-DRADIOLIB_EXCLUDE_CC1101=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
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
#-DBUILD_EPOCH=$UNIX_TIME
;-D OLED_PL
monitor_speed = 115200
monitor_filters = direct
lib_deps =
jgromes/RadioLib@~7.0.2
https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95 ; ESP8266_SSD1306
mathertel/OneButton@~2.6.1 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0
nanopb/Nanopb@^0.4.9
erriez/ErriezCRC32@^1.0.1
https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95
mathertel/OneButton@2.6.1
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0
nanopb/Nanopb@0.4.9
erriez/ErriezCRC32@1.0.1
; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck
check_skip_packages = yes
check_flags =
-DAPP_VERSION=1.0.0
--suppressions-list=suppressions.txt
--inline-suppr
-DAPP_VERSION=1.0.0
--suppressions-list=suppressions.txt
--inline-suppr
; Common settings for conventional (non Portduino) Arduino targets
[arduino_base]
framework = arduino
lib_deps =
${env.lib_deps}
end2endzone/NonBlockingRTTTL@^1.3.0
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
${env.lib_deps}
end2endzone/NonBlockingRTTTL@1.3.0
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
build_flags = ${env.build_flags} -Os
build_src_filter = ${env.build_src_filter} -<platform/portduino/>
; Common libs for communicating over TCP/IP networks such as MQTT
[networking_base]
lib_deps =
knolleary/PubSubClient@^2.8
arduino-libraries/NTPClient@^3.1.0
arcao/Syslog@^2.0.0
knolleary/PubSubClient@2.8
arduino-libraries/NTPClient@3.1.0
arcao/Syslog@2.0.0
[radiolib_base]
lib_deps =
jgromes/RadioLib@7.1.0
; Common libs for environmental measurements in telemetry module
; (not included in native / portduino)
[environmental_base]
lib_deps =
adafruit/Adafruit BusIO@^1.16.1
adafruit/Adafruit Unified Sensor@^1.1.11
adafruit/Adafruit BMP280 Library@^2.6.8
adafruit/Adafruit BMP085 Library@^1.2.4
adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BMP3XX Library@^2.1.5
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
adafruit/Adafruit PM25 AQI Sensor@^1.1.1
adafruit/Adafruit MPU6050@^2.2.4
adafruit/Adafruit LIS3DH@^1.3.0
adafruit/Adafruit AHTX0@^2.0.5
adafruit/Adafruit LSM6DS@^4.7.2
adafruit/Adafruit VEML7700 Library@^2.1.6
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
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@^1.1.2
adafruit/Adafruit MLX90614 Library@^2.1.5
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502
boschsensortec/BME68x Sensor Library@^1.1.40407
https://github.com/KodinLanewave/INA3221@^1.0.1
lewisxhe/SensorLib@0.2.0
mprograms/QMC5883LCompass@^1.2.0
https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d
https://github.com/gjelsoe/STK8xxx-Accelerometer.git#v0.1.1
adafruit/Adafruit BusIO@1.16.2
adafruit/Adafruit Unified Sensor@1.1.14
adafruit/Adafruit BMP280 Library@2.6.8
adafruit/Adafruit BMP085 Library@1.2.4
adafruit/Adafruit BME280 Library@2.2.4
adafruit/Adafruit BMP3XX Library@2.1.5
adafruit/Adafruit MCP9808 Library@2.0.2
adafruit/Adafruit INA260 Library@1.5.2
adafruit/Adafruit INA219@1.2.3
adafruit/Adafruit MAX1704X@1.0.3
adafruit/Adafruit SHTC3 Library@1.0.1
adafruit/Adafruit LPS2X@2.0.6
adafruit/Adafruit SHT31 Library@2.2.2
adafruit/Adafruit PM25 AQI Sensor@1.1.1
adafruit/Adafruit MPU6050@2.2.6
adafruit/Adafruit LIS3DH@1.3.0
adafruit/Adafruit AHTX0@2.0.5
adafruit/Adafruit LSM6DS@4.7.3
adafruit/Adafruit VEML7700 Library@2.1.6
adafruit/Adafruit SHT4x Library@1.0.5
adafruit/Adafruit TSL2591 Library@1.4.5
sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@1.0.6
sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.2.13
ClosedCube OPT3001@1.1.2
emotibit/EmotiBit MLX90632@1.0.8
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
adafruit/Adafruit MLX90614 Library@2.1.5
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502
boschsensortec/BME68x Sensor Library@1.1.40407
https://github.com/KodinLanewave/INA3221@1.0.1
mprograms/QMC5883LCompass@1.2.3
dfrobot/DFRobot_RTU@1.0.3
https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d

View File

@@ -1 +0,0 @@
curfirmwareversion.xml

View File

@@ -21,7 +21,7 @@ namespace concurrency
class AmbientLightingThread : public concurrency::OSThread
{
public:
explicit AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLightingThread")
explicit AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLighting")
{
notifyDeepSleepObserver.observe(&notifyDeepSleep); // Let us know when shutdown() is issued.
@@ -42,18 +42,18 @@ class AmbientLightingThread : public concurrency::OSThread
#ifdef HAS_NCP5623
_type = type;
if (_type == ScanI2C::DeviceType::NONE) {
LOG_DEBUG("AmbientLightingThread disabling due to no RGB leds found on I2C bus");
LOG_DEBUG("AmbientLighting Disable due to no RGB leds found on I2C bus");
disable();
return;
}
#endif
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
if (!moduleConfig.ambient_lighting.led_state) {
LOG_DEBUG("AmbientLightingThread disabling due to moduleConfig.ambient_lighting.led_state OFF");
LOG_DEBUG("AmbientLighting Disable due to moduleConfig.ambient_lighting.led_state OFF");
disable();
return;
}
LOG_DEBUG("AmbientLightingThread initializing");
LOG_DEBUG("AmbientLighting init");
#ifdef HAS_NCP5623
if (_type == ScanI2C::NCP5623) {
rgb.begin();
@@ -106,27 +106,27 @@ class AmbientLightingThread : public concurrency::OSThread
rgb.setRed(0);
rgb.setGreen(0);
rgb.setBlue(0);
LOG_INFO("Turn Off NCP5623 Ambient lighting.");
LOG_INFO("OFF: NCP5623 Ambient lighting");
#endif
#ifdef HAS_NEOPIXEL
pixels.clear();
pixels.show();
LOG_INFO("Turn Off NeoPixel Ambient lighting.");
LOG_INFO("OFF: NeoPixel Ambient lighting");
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255 - 0);
analogWrite(RGBLED_GREEN, 255 - 0);
analogWrite(RGBLED_BLUE, 255 - 0);
LOG_INFO("Turn Off Ambient lighting RGB Common Anode.");
LOG_INFO("OFF: Ambient light RGB Common Anode");
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, 0);
analogWrite(RGBLED_GREEN, 0);
analogWrite(RGBLED_BLUE, 0);
LOG_INFO("Turn Off Ambient lighting RGB Common Cathode.");
LOG_INFO("OFF: Ambient light RGB Common Cathode");
#endif
#ifdef UNPHONE
unphone.rgb(0, 0, 0);
LOG_INFO("Turn Off unPhone Ambient lighting.");
LOG_INFO("OFF: unPhone Ambient lighting");
#endif
return 0;
}
@@ -138,9 +138,8 @@ class AmbientLightingThread : public concurrency::OSThread
rgb.setRed(moduleConfig.ambient_lighting.red);
rgb.setGreen(moduleConfig.ambient_lighting.green);
rgb.setBlue(moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing NCP5623 Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d",
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Init NCP5623 Ambient light w/ current=%d, red=%d, green=%d, blue=%d", moduleConfig.ambient_lighting.current,
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#endif
#ifdef HAS_NEOPIXEL
pixels.fill(pixels.Color(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
@@ -158,7 +157,7 @@ class AmbientLightingThread : public concurrency::OSThread
#endif
#endif
pixels.show();
LOG_DEBUG("Initializing NeoPixel Ambient lighting w/ brightness(current)=%d, red=%d, green=%d, blue=%d",
LOG_DEBUG("Init NeoPixel Ambient light w/ brightness(current)=%d, red=%d, green=%d, blue=%d",
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
moduleConfig.ambient_lighting.blue);
#endif
@@ -166,21 +165,21 @@ class AmbientLightingThread : public concurrency::OSThread
analogWrite(RGBLED_RED, 255 - moduleConfig.ambient_lighting.red);
analogWrite(RGBLED_GREEN, 255 - moduleConfig.ambient_lighting.green);
analogWrite(RGBLED_BLUE, 255 - moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing Ambient lighting RGB Common Anode w/ red=%d, green=%d, blue=%d",
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Init Ambient light RGB Common Anode w/ red=%d, green=%d, blue=%d", moduleConfig.ambient_lighting.red,
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, moduleConfig.ambient_lighting.red);
analogWrite(RGBLED_GREEN, moduleConfig.ambient_lighting.green);
analogWrite(RGBLED_BLUE, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing Ambient lighting RGB Common Cathode w/ red=%d, green=%d, blue=%d",
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Init Ambient light RGB Common Cathode w/ red=%d, green=%d, blue=%d", moduleConfig.ambient_lighting.red,
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#endif
#ifdef UNPHONE
unphone.rgb(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing unPhone Ambient lighting w/ red=%d, green=%d, blue=%d", moduleConfig.ambient_lighting.red,
LOG_DEBUG("Init unPhone Ambient light w/ red=%d, green=%d, blue=%d", moduleConfig.ambient_lighting.red,
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#endif
}
};
} // namespace concurrency
} // namespace concurrency

View File

@@ -16,7 +16,7 @@
class AudioThread : public concurrency::OSThread
{
public:
AudioThread() : OSThread("AudioThread") { initOutput(); }
AudioThread() : OSThread("Audio") { initOutput(); }
void beginRttl(const void *data, uint32_t len)
{
@@ -64,7 +64,7 @@ class AudioThread : public concurrency::OSThread
void initOutput()
{
audioOut = new AudioOutputI2S(1, AudioOutputI2S::EXTERNAL_I2S);
audioOut->SetPinout(DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT);
audioOut->SetPinout(DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_MCLK);
audioOut->SetGain(0.2);
};

View File

@@ -1,4 +1,5 @@
#include "ButtonThread.h"
#include "../userPrefs.h"
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_GPS
#include "GPS.h"
@@ -26,20 +27,25 @@ using namespace concurrency;
ButtonThread *buttonThread; // Declared extern in header
volatile ButtonThread::ButtonEventType ButtonThread::btnEvent = ButtonThread::BUTTON_EVENT_NONE;
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
OneButton ButtonThread::userButton; // Get reference to static member
#endif
ButtonThread::ButtonThread() : OSThread("Button")
{
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
#if defined(ARCH_PORTDUINO)
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC) {
this->userButton = OneButton(settingsMap[user], true, true);
LOG_DEBUG("Using GPIO%02d for button", settingsMap[user]);
LOG_DEBUG("Use GPIO%02d for button", settingsMap[user]);
}
#elif defined(BUTTON_PIN)
int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin
#if !defined(USERPREFS_BUTTON_PIN)
int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin
#endif
#ifdef USERPREFS_BUTTON_PIN
int pin = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN; // Resolved button pin
#endif
#if defined(HELTEC_CAPSULE_SENSOR_V3)
this->userButton = OneButton(pin, false, false);
#elif defined(BUTTON_ACTIVE_LOW)
@@ -47,7 +53,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
#else
this->userButton = OneButton(pin, true, true);
#endif
LOG_DEBUG("Using GPIO%02d for button", pin);
LOG_DEBUG("Use GPIO%02d for button", pin);
#endif
#ifdef INPUT_PULLUP_SENSE
@@ -59,7 +65,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
#endif
#endif
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
userButton.attachClick(userButtonPressed);
userButton.setClickMs(BUTTON_CLICK_MS);
userButton.setPressMs(BUTTON_LONGPRESS_MS);
@@ -102,7 +108,7 @@ int32_t ButtonThread::runOnce()
// If the button is pressed we suppress CPU sleep until release
canSleep = true; // Assume we should not keep the board awake
#if defined(BUTTON_PIN)
#if defined(BUTTON_PIN) || defined(USERPREFS_BUTTON_PIN)
userButton.tick();
canSleep &= userButton.isIdle();
#elif defined(ARCH_PORTDUINO)
@@ -130,7 +136,12 @@ int32_t ButtonThread::runOnce()
return 50;
}
#ifdef BUTTON_PIN
#if !defined(USERPREFS_BUTTON_PIN)
if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
#endif
#if defined(USERPREFS_BUTTON_PIN)
if (((config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN) !=
#endif
moduleConfig.canned_message.inputbroker_pin_press) ||
!(moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.rotary1_enabled) ||
!moduleConfig.canned_message.enabled) {
@@ -244,7 +255,12 @@ void ButtonThread::attachButtonInterrupts()
#elif defined(BUTTON_PIN)
// Interrupt for user button, during normal use. Improves responsiveness.
attachInterrupt(
#if !defined(USERPREFS_BUTTON_PIN)
config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN,
#endif
#if defined(USERPREFS_BUTTON_PIN)
config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN,
#endif
[]() {
ButtonThread::userButton.tick();
runASAP = true;
@@ -273,8 +289,13 @@ void ButtonThread::detachButtonInterrupts()
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC)
detachInterrupt(settingsMap[user]);
#elif defined(BUTTON_PIN)
#if !defined(USERPREFS_BUTTON_PIN)
detachInterrupt(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
#endif
#if defined(USERPREFS_BUTTON_PIN)
detachInterrupt(config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN);
#endif
#endif
#ifdef BUTTON_PIN_ALT
detachInterrupt(BUTTON_PIN_ALT);
@@ -315,7 +336,7 @@ void ButtonThread::userButtonMultiPressed(void *callerThread)
// Non-static method, runs during callback. Grabs info while still valid
void ButtonThread::storeClickCount()
{
#ifdef BUTTON_PIN
#if defined(BUTTON_PIN) || defined(USERPREFS_BUTTON_PIN)
multipressClickCount = userButton.getNumberClicks();
#endif
}

View File

@@ -38,7 +38,7 @@ class ButtonThread : public concurrency::OSThread
void storeClickCount();
private:
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
static OneButton userButton; // Static - accessed from an interrupt
#endif
#ifdef BUTTON_PIN_ALT

View File

@@ -231,7 +231,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
#ifdef ARCH_ESP32
listDir(file.path(), levels - 1, del);
if (del) {
LOG_DEBUG("Removing %s", file.path());
LOG_DEBUG("Remove %s", file.path());
strncpy(buffer, file.path(), sizeof(buffer));
file.close();
FSCom.rmdir(buffer);
@@ -241,7 +241,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
listDir(file.name(), levels - 1, del);
if (del) {
LOG_DEBUG("Removing %s", file.name());
LOG_DEBUG("Remove %s", file.name());
strncpy(buffer, file.name(), sizeof(buffer));
file.close();
FSCom.rmdir(buffer);
@@ -257,7 +257,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
} else {
#ifdef ARCH_ESP32
if (del) {
LOG_DEBUG("Deleting %s", file.path());
LOG_DEBUG("Delete %s", file.path());
strncpy(buffer, file.path(), sizeof(buffer));
file.close();
FSCom.remove(buffer);
@@ -267,7 +267,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
}
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
if (del) {
LOG_DEBUG("Deleting %s", file.name());
LOG_DEBUG("Delete %s", file.name());
strncpy(buffer, file.name(), sizeof(buffer));
file.close();
FSCom.remove(buffer);
@@ -284,7 +284,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
}
#ifdef ARCH_ESP32
if (del) {
LOG_DEBUG("Removing %s", root.path());
LOG_DEBUG("Remove %s", root.path());
strncpy(buffer, root.path(), sizeof(buffer));
root.close();
FSCom.rmdir(buffer);
@@ -293,7 +293,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
}
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
if (del) {
LOG_DEBUG("Removing %s", root.name());
LOG_DEBUG("Remove %s", root.name());
strncpy(buffer, root.name(), sizeof(buffer));
root.close();
FSCom.rmdir(buffer);
@@ -329,7 +329,7 @@ void fsInit()
{
#ifdef FSCom
if (!FSBegin()) {
LOG_ERROR("Filesystem mount Failed.");
LOG_ERROR("Filesystem mount failed");
// assert(0); This auto-formats the partition, so no need to fail here.
}
#if defined(ARCH_ESP32)

View File

@@ -50,9 +50,6 @@ class GPSStatus : public Status
int32_t getLatitude() const
{
if (config.position.fixed_position) {
#ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed latitude");
#endif
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
return node->position.latitude_i;
} else {
@@ -63,9 +60,6 @@ class GPSStatus : public Status
int32_t getLongitude() const
{
if (config.position.fixed_position) {
#ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed longitude");
#endif
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
return node->position.longitude_i;
} else {
@@ -76,9 +70,6 @@ class GPSStatus : public Status
int32_t getAltitude() const
{
if (config.position.fixed_position) {
#ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed altitude");
#endif
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
return node->position.altitude;
} else {
@@ -94,7 +85,7 @@ class GPSStatus : public Status
bool matches(const GPSStatus *newStatus) const
{
#ifdef GPS_EXTRAVERBOSE
#ifdef GPS_DEBUG
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x", newStatus->p.timestamp, p.timestamp);
#endif
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||

View File

@@ -12,7 +12,6 @@ void GpioVirtPin::set(bool value)
void GpioHwPin::set(bool value)
{
// if (num == 3) LOG_DEBUG("Setting pin %d to %d", num, value);
pinMode(num, OUTPUT);
digitalWrite(num, value);
}
@@ -66,7 +65,7 @@ GpioBinaryTransformer::GpioBinaryTransformer(GpioVirtPin *inPin1, GpioVirtPin *i
assert(!inPin2->dependentPin); // We only allow one dependent pin
inPin2->dependentPin = this;
// Don't update at construction time, because various GpioPins might be global constructor based not yet initied because
// Don't update at construction time, because various GpioPins might be global constructor based not yet initiated because
// order of operations for global constructors is not defined.
// update();
}
@@ -88,7 +87,6 @@ void GpioBinaryTransformer::update()
newValue = (GpioVirtPin::PinState)(p1 && p2);
break;
case Or:
// LOG_DEBUG("Doing GPIO OR");
newValue = (GpioVirtPin::PinState)(p1 || p2);
break;
case Xor:
@@ -101,4 +99,4 @@ void GpioBinaryTransformer::update()
set(newValue);
}
GpioSplitter::GpioSplitter(GpioPin *outPin1, GpioPin *outPin2) : outPin1(outPin1), outPin2(outPin2) {}
GpioSplitter::GpioSplitter(GpioPin *outPin1, GpioPin *outPin2) : outPin1(outPin1), outPin2(outPin2) {}

View File

@@ -154,9 +154,16 @@ static void adcEnable()
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
#ifdef ADC_USE_PULLUP
pinMode(ADC_CTRL, INPUT_PULLUP);
#else
#ifdef HELTEC_V3
pinMode(ADC_CTRL, INPUT);
uint8_t adc_ctl_enable_value = !(digitalRead(ADC_CTRL));
pinMode(ADC_CTRL, OUTPUT);
digitalWrite(ADC_CTRL, adc_ctl_enable_value);
#else
pinMode(ADC_CTRL, OUTPUT);
digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED);
#endif
#endif
delay(10);
#endif
@@ -167,10 +174,14 @@ static void adcDisable()
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
#ifdef ADC_USE_PULLUP
pinMode(ADC_CTRL, INPUT_PULLDOWN);
#else
#ifdef HELTEC_V3
pinMode(ADC_CTRL, ANALOG);
#else
digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED);
#endif
#endif
#endif
}
#endif
@@ -240,7 +251,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(HAS_PMU) && \
!MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
if (hasINA()) {
LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage", config.power.device_battery_ina_address);
return getINAVoltage();
}
#endif
@@ -260,7 +270,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 (!Throttle::isWithinTimespanMs(last_read_time_ms, min_read_interval)) {
if (!initial_read_done || !Throttle::isWithinTimespanMs(last_read_time_ms, min_read_interval)) {
last_read_time_ms = millis();
uint32_t raw = 0;
@@ -360,7 +370,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
/**
* return true if there is a battery installed in this unit
*/
// if we have a integrated device with a battery, we can assume that the battery is always connected
#ifdef BATTERY_IMMUTABLE
virtual bool isBatteryConnect() override { return true; }
#else
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
#endif
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
@@ -495,7 +510,7 @@ bool Power::analogInit()
#endif
#ifdef BATTERY_PIN
LOG_DEBUG("Using analog input %d for battery level", BATTERY_PIN);
LOG_DEBUG("Use analog input %d for battery level", BATTERY_PIN);
// disable any internal pullups
pinMode(BATTERY_PIN, INPUT);
@@ -526,18 +541,18 @@ bool Power::analogInit()
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_characs);
// show ADC characterization base
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
LOG_INFO("ADCmod: ADC characterization based on Two Point values stored in eFuse");
LOG_INFO("ADC config based on Two Point values stored in eFuse");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
LOG_INFO("ADCmod: ADC characterization based on reference voltage stored in eFuse");
LOG_INFO("ADC config based on reference voltage stored in eFuse");
}
#ifdef CONFIG_IDF_TARGET_ESP32S3
// ESP32S3
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP_FIT) {
LOG_INFO("ADCmod: ADC Characterization based on Two Point values and fitting curve coefficients stored in eFuse");
LOG_INFO("ADC config based on Two Point values and fitting curve coefficients stored in eFuse");
}
#endif
else {
LOG_INFO("ADCmod: ADC characterization based on default reference voltage");
LOG_INFO("ADC config based on default reference voltage");
}
#endif // ARCH_ESP32
@@ -598,7 +613,7 @@ void Power::shutdown()
#ifdef PIN_LED3
ledOff(PIN_LED3);
#endif
doDeepSleep(DELAY_FOREVER, false);
doDeepSleep(DELAY_FOREVER, false, false);
#endif
}
@@ -624,7 +639,7 @@ void Power::readPowerStatus()
batteryChargePercent = batteryLevel->getBatteryPercent();
} else {
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
// In that case, we compute an estimate of the charge percent based on open circuite voltage table defined
// In that case, we compute an estimate of the charge percent based on open circuit voltage table defined
// in power.h
batteryChargePercent = clamp((int)(((batteryVoltageMv - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS)) * 1e2) /
((OCV[0] * NUM_CELLS) - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS))),
@@ -706,9 +721,9 @@ void Power::readPowerStatus()
if (low_voltage_counter > 10) {
#ifdef ARCH_NRF52
// We can't trigger deep sleep on NRF52, it's freezing the board
LOG_DEBUG("Low voltage detected, but not triggering deep sleep");
LOG_DEBUG("Low voltage detected, but not trigger deep sleep");
#else
LOG_INFO("Low voltage detected, triggering deep sleep");
LOG_INFO("Low voltage detected, trigger deep sleep");
powerFSM.trigger(EVENT_LOW_BATTERY);
#endif
}
@@ -800,22 +815,22 @@ bool Power::axpChipInit()
if (!PMU) {
PMU = new XPowersAXP2101(*w);
if (!PMU->init()) {
LOG_WARN("Failed to find AXP2101 power management");
LOG_WARN("No AXP2101 power management");
delete PMU;
PMU = NULL;
} else {
LOG_INFO("AXP2101 PMU init succeeded, using AXP2101 PMU");
LOG_INFO("AXP2101 PMU init succeeded");
}
}
if (!PMU) {
PMU = new XPowersAXP192(*w);
if (!PMU->init()) {
LOG_WARN("Failed to find AXP192 power management");
LOG_WARN("No AXP192 power management");
delete PMU;
PMU = NULL;
} else {
LOG_INFO("AXP192 PMU init succeeded, using AXP192 PMU");
LOG_INFO("AXP192 PMU init succeeded");
}
}

View File

@@ -53,16 +53,21 @@ static bool isPowered()
static void sdsEnter()
{
LOG_DEBUG("Enter state: SDS");
LOG_DEBUG("State: SDS");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false);
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, false);
}
static void lowBattSDSEnter()
{
LOG_DEBUG("State: Lower batt SDS");
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, true);
}
extern Power *power;
static void shutdownEnter()
{
LOG_DEBUG("Enter state: SHUTDOWN");
LOG_DEBUG("State: SHUTDOWN");
power->shutdown();
}
@@ -105,7 +110,7 @@ static void lsIdle()
wakeCause2 = doLightSleep(100); // leave led on for 1ms
secsSlept += sleepTime;
// LOG_INFO("sleeping, flash led!");
// LOG_INFO("Sleep, flash led!");
break;
case ESP_SLEEP_WAKEUP_UART:
@@ -137,7 +142,7 @@ static void lsIdle()
} else {
// Time to stop sleeping!
ledBlink.set(false);
LOG_INFO("Reached ls_secs, servicing loop()");
LOG_INFO("Reached ls_secs, service loop()");
powerFSM.trigger(EVENT_WAKE_TIMER);
}
#endif
@@ -150,7 +155,7 @@ static void lsExit()
static void nbEnter()
{
LOG_DEBUG("Enter state: NB");
LOG_DEBUG("State: NB");
screen->setOn(false);
#ifdef ARCH_ESP32
// Only ESP32 should turn off bluetooth
@@ -168,7 +173,7 @@ static void darkEnter()
static void serialEnter()
{
LOG_DEBUG("Enter state: SERIAL");
LOG_DEBUG("State: SERIAL");
setBluetoothEnable(false);
screen->setOn(true);
screen->print("Serial connected\n");
@@ -183,9 +188,9 @@ static void serialExit()
static void powerEnter()
{
// LOG_DEBUG("Enter state: POWER");
// LOG_DEBUG("State: POWER");
if (!isPowered()) {
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
// If we got here, we are in the wrong state - we should be in powered, let that state handle things
LOG_INFO("Loss of power in Powered");
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
} else {
@@ -222,7 +227,7 @@ static void powerExit()
static void onEnter()
{
LOG_DEBUG("Enter state: ON");
LOG_DEBUG("State: ON");
screen->setOn(true);
setBluetoothEnable(true);
}
@@ -230,7 +235,7 @@ static void onEnter()
static void onIdle()
{
if (isPowered()) {
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
// If we got here, we are in the wrong state - we should be in powered, let that state handle things
powerFSM.trigger(EVENT_POWER_CONNECTED);
}
}
@@ -242,11 +247,12 @@ static void screenPress()
static void bootEnter()
{
LOG_DEBUG("Enter state: BOOT");
LOG_DEBUG("State: BOOT");
}
State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN");
State stateSDS(sdsEnter, NULL, NULL, "SDS");
State stateLowBattSDS(lowBattSDSEnter, NULL, NULL, "SDS");
State stateLS(lsEnter, lsIdle, lsExit, "LS");
State stateNB(nbEnter, NULL, NULL, "NB");
State stateDARK(darkEnter, NULL, NULL, "DARK");
@@ -291,12 +297,12 @@ void PowerFSM_setup()
"Press"); // Allow button to work while in serial API
// Handle critically low power battery by forcing deep sleep
powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateLS, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateNB, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateDARK, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateON, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateSERIAL, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateBOOT, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateLS, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateNB, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateDARK, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateON, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateSERIAL, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
// Handle being told to power off
powerFSM.add_transition(&stateBOOT, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
@@ -371,7 +377,7 @@ void PowerFSM_setup()
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
#ifdef ARCH_ESP32
// See: https://github.com/meshtastic/firmware/issues/1071
// Don't add power saving transitions if we are a power saving tracker or sensor. Sleep will be initiatiated through the
// Don't add power saving transitions if we are a power saving tracker or sensor. Sleep will be initiated through the
// modules
if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) {
powerFSM.add_timed_transition(&stateNB, &stateLS,

View File

@@ -51,9 +51,9 @@ class RedirectablePrint : public Print
protected:
/// Subclasses can override if they need to change how we format over the serial port
virtual void log_to_serial(const char *logLevel, const char *format, va_list arg);
meshtastic_LogRecord_Level getLogLevel(const char *logLevel);
private:
void log_to_syslog(const char *logLevel, const char *format, va_list arg);
void log_to_ble(const char *logLevel, const char *format, va_list arg);
meshtastic_LogRecord_Level getLogLevel(const char *logLevel);
};

View File

@@ -99,25 +99,7 @@ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
void SerialConsole::log_to_serial(const char *logLevel, const char *format, va_list arg)
{
if (usingProtobufs && config.security.debug_log_api_enabled) {
meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset
switch (logLevel[0]) {
case 'D':
ll = meshtastic_LogRecord_Level_DEBUG;
break;
case 'I':
ll = meshtastic_LogRecord_Level_INFO;
break;
case 'W':
ll = meshtastic_LogRecord_Level_WARNING;
break;
case 'E':
ll = meshtastic_LogRecord_Level_ERROR;
break;
case 'C':
ll = meshtastic_LogRecord_Level_CRITICAL;
break;
}
meshtastic_LogRecord_Level ll = RedirectablePrint::getLogLevel(logLevel);
auto thread = concurrency::OSThread::currentThread;
emitLogRecord(ll, thread ? thread->ThreadName.c_str() : "", format, arg);
} else

View File

@@ -13,17 +13,17 @@ void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
{
if (reportType == TX_LOG) {
LOG_DEBUG("Packet transmitted : %ums", airtime_ms);
LOG_DEBUG("Packet TX: %ums", airtime_ms);
this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms;
air_period_tx[0] = air_period_tx[0] + airtime_ms;
this->utilizationTX[this->getPeriodUtilHour()] = this->utilizationTX[this->getPeriodUtilHour()] + airtime_ms;
} else if (reportType == RX_LOG) {
LOG_DEBUG("Packet received : %ums", airtime_ms);
LOG_DEBUG("Packet RX: %ums", airtime_ms);
this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms;
air_period_rx[0] = air_period_rx[0] + airtime_ms;
} else if (reportType == RX_ALL_LOG) {
LOG_DEBUG("Packet received (noise?) : %ums", airtime_ms);
LOG_DEBUG("Packet RX (noise?) : %ums", airtime_ms);
this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms;
}
@@ -50,7 +50,7 @@ void AirTime::airtimeRotatePeriod()
{
if (this->airtimes.lastPeriodIndex != this->currentPeriodIndex()) {
LOG_DEBUG("Rotating airtimes to a new period = %u", this->currentPeriodIndex());
LOG_DEBUG("Rotate airtimes to a new period = %u", this->currentPeriodIndex());
for (int i = PERIODS_TO_LOG - 2; i >= 0; --i) {
this->airtimes.periodTX[i + 1] = this->airtimes.periodTX[i];
@@ -105,7 +105,6 @@ float AirTime::channelUtilizationPercent()
uint32_t sum = 0;
for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) {
sum += this->channelUtilization[i];
// LOG_DEBUG("ChanUtilArray %u %u", i, this->channelUtilization[i]);
}
return (float(sum) / float(CHANNEL_UTILIZATION_PERIODS * 10 * 1000)) * 100;
@@ -127,7 +126,7 @@ bool AirTime::isTxAllowedChannelUtil(bool polite)
if (channelUtilizationPercent() < percentage) {
return true;
} else {
LOG_WARN("Channel utilization is >%d percent. Skipping this opportunity to send.", percentage);
LOG_WARN("Ch. util >%d%%. Skip send", percentage);
return false;
}
}
@@ -138,8 +137,7 @@ bool AirTime::isTxAllowedAirUtil()
if (utilizationTXPercent() < myRegion->dutyCycle * polite_duty_cycle_percent / 100) {
return true;
} else {
LOG_WARN("Tx air utilization is >%f percent. Skipping this opportunity to send.",
myRegion->dutyCycle * polite_duty_cycle_percent / 100);
LOG_WARN("TX air util. >%f%%. Skip send", myRegion->dutyCycle * polite_duty_cycle_percent / 100);
return false;
}
}
@@ -208,14 +206,5 @@ int32_t AirTime::runOnce()
this->utilizationTX[utilPeriodTX] = 0;
}
}
/*
LOG_DEBUG("utilPeriodTX %d TX Airtime %3.2f%", utilPeriodTX, airTime->utilizationTXPercent());
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
LOG_DEBUG(
"%d,", this->utilizationTX[i]
);
}
LOG_DEBUG("");
*/
return (1000 * 1);
}
}

View File

@@ -55,6 +55,18 @@ void playBeep()
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playGPSEnableBeep()
{
ToneDuration melody[] = {{NOTE_C3, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}, {NOTE_CS4, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playGPSDisableBeep()
{
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}, {NOTE_C3, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playStartMelody()
{
ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8}, {NOTE_AS3, DURATION_1_8}, {NOTE_CS4, DURATION_1_4}};

View File

@@ -3,3 +3,5 @@
void playBeep();
void playStartMelody();
void playShutdownMelody();
void playGPSEnableBeep();
void playGPSDisableBeep();

View File

@@ -32,12 +32,12 @@ IRAM_ATTR bool NotifiedWorkerThread::notifyCommon(uint32_t v, bool overwrite)
notification = v;
if (debugNotification) {
LOG_DEBUG("setting notification %d", v);
LOG_DEBUG("Set notification %d", v);
}
return true;
} else {
if (debugNotification) {
LOG_DEBUG("dropping notification %d", v);
LOG_DEBUG("Drop notification %d", v);
}
return false;
}
@@ -67,7 +67,7 @@ bool NotifiedWorkerThread::notifyLater(uint32_t delay, uint32_t v, bool overwrit
if (didIt) { // If we didn't already have something queued, override the delay to be larger
setIntervalFromNow(delay); // a new version of setInterval relative to the current time
if (debugNotification) {
LOG_DEBUG("delaying notification %u", delay);
LOG_DEBUG("Delay notification %u", delay);
}
}

View File

@@ -114,6 +114,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define CARDKB_ADDR 0x5F
#define TDECK_KB_ADDR 0x55
#define BBQ10_KB_ADDR 0x1F
#define MPR121_KB_ADDR 0x5A
// -----------------------------------------------------------------------------
// SENSOR
@@ -135,6 +136,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LPS22HB_ADDR_ALT 0x5D
#define SHT31_4x_ADDR 0x44
#define PMSA0031_ADDR 0x12
#define QMA6100P_ADDR 0x12
#define AHT10_ADDR 0x38
#define RCWL9620_ADDR 0x57
#define VEML7700_ADDR 0x10
@@ -151,8 +153,9 @@ 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 STK8BXX_ADDR 0x18
#define LIS3DH_ADDR 0x18
#define LIS3DH_ADDR_ALT 0x19
#define BMA423_ADDR 0x19
#define LSM6DS3_ADDR 0x6A
#define BMX160_ADDR 0x69
@@ -205,6 +208,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef GPS_BAUDRATE
#define GPS_BAUDRATE 9600
#define GPS_BAUDRATE_FIXED 0
#else
#define GPS_BAUDRATE_FIXED 1
#endif
/* Step #2: follow with defines common to the architecture;

View File

@@ -31,14 +31,14 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004};
return firstOfOrNONE(4, types);
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004, MPR121KB};
return firstOfOrNONE(5, types);
}
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
{
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948};
return firstOfOrNONE(7, types);
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948, QMA6100P};
return firstOfOrNONE(8, types);
}
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const

View File

@@ -39,6 +39,7 @@ class ScanI2C
QMC5883L,
HMC5883L,
PMSA0031,
QMA6100P,
MPU6050,
LIS3DH,
BMA423,
@@ -61,7 +62,8 @@ class ScanI2C
STK8BAXX,
ICM20948,
MAX30102,
TPS65233
TPS65233,
MPR121KB
} DeviceType;
// typedef uint8_t DeviceAddress;

View File

@@ -7,7 +7,8 @@
#include "linux/LinuxHardwareI2C.h"
#endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "main.h" // atecc
#include "main.h" // atecc
#include "meshUtils.h" // vformat
#endif
// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp
@@ -149,7 +150,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
LOG_DEBUG("Scanning for I2C devices on port %d", port);
LOG_DEBUG("Scan for I2C devices on port %d", port);
uint8_t err;
@@ -172,11 +173,20 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
#endif
for (addr.address = 1; addr.address < 127; addr.address++) {
// We only need to scan 112 addresses, the rest is reserved for special purposes
// 0x00 General Call
// 0x01 CBUS addresses
// 0x02 Reserved for different bus formats
// 0x03 Reserved for future purposes
// 0x04-0x07 High Speed Master Code
// 0x78-0x7B 10-bit slave addressing
// 0x7C-0x7F Reserved for future purposes
for (addr.address = 8; addr.address < 120; addr.address++) {
if (asize != 0) {
if (!in_array(address, asize, addr.address))
continue;
LOG_DEBUG("Scanning address 0x%x", addr.address);
LOG_DEBUG("Scan address 0x%x", addr.address);
}
i2cBus->beginTransmission(addr.address);
#ifdef ARCH_PORTDUINO
@@ -243,6 +253,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found");
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found");
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found");
#ifdef HAS_NCP5623
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found");
@@ -303,19 +314,34 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
case INA3221_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
LOG_DEBUG("Register MFG_UID: 0x%x", registerValue);
LOG_DEBUG("Register MFG_UID FE: 0x%x", registerValue);
if (registerValue == 0x5449) {
LOG_INFO("INA3221 sensor found at address 0x%x", (uint8_t)addr.address);
type = INA3221;
} else {
LOG_INFO("DFRobot Lark weather station found at address 0x%x", (uint8_t)addr.address);
type = DFROBOT_LARK;
/* check the first 2 bytes of the 6 byte response register
LARK FW 1.0 should return:
RESPONSE_STATUS STATUS_SUCCESS (0x53)
RESPONSE_CMD CMD_GET_VERSION (0x05)
RESPONSE_LEN_L 0x02
RESPONSE_LEN_H 0x00
RESPONSE_PAYLOAD 0x01
RESPONSE_PAYLOAD+1 0x00
*/
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x05), 2);
LOG_DEBUG("Register MFG_UID 05: 0x%x", registerValue);
if (registerValue == 0x5305) {
LOG_INFO("DFRobot Lark weather station found at address 0x%x", (uint8_t)addr.address);
type = DFROBOT_LARK;
}
// else: probably a RAK12500/UBLOX GPS on I2C
}
break;
case MCP9808_ADDR:
// 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.
{
#ifdef HAS_STK8XXX
// Check register 0x00 for 0x8700 response to ID STK8BA53 chip.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 2);
if (registerValue == 0x8700) {
@@ -323,6 +349,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
LOG_INFO("STK8BAXX accelerometer found");
break;
}
#endif
// Check register 0x07 for 0x0400 response to ID MCP9808 chip.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
@@ -393,8 +420,22 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found")
SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L 3-Axis digital compass found")
#ifdef HAS_QMA6100P
SCAN_SIMPLE_CASE(QMA6100P_ADDR, QMA6100P, "QMA6100P accelerometer found")
#else
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found")
SCAN_SIMPLE_CASE(BMA423_ADDR, BMA423, "BMA423 accelerometer found");
#endif
case BMA423_ADDR: // this can also be LIS3DH_ADDR_ALT
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");
} else {
type = BMA423;
LOG_INFO("BMA423 accelerometer found");
}
break;
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3 accelerometer found at address 0x%x", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535 I2C expander found");
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555 I2C expander found");
@@ -408,7 +449,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
#ifdef HAS_TPS65233
SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233 BIAS-T found");
#endif
SCAN_SIMPLE_CASE(MLX90614_ADDR_DEF, MLX90614, "MLX90614 IR temp sensor found");
case MLX90614_ADDR_DEF:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1);
if (registerValue == 0x5a) {
type = MLX90614;
LOG_INFO("MLX90614 IR temp sensor found");
} else {
type = MPR121KB;
LOG_INFO("MPR121KB keyboard found");
}
break;
case ICM20948_ADDR: // same as BMX160_ADDR
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR

View File

@@ -1,19 +0,0 @@
#if 0
// Turn off for now
uint32_t axpDebugRead()
{
axp.debugCharging();
LOG_DEBUG("vbus current %f", axp.getVbusCurrent());
LOG_DEBUG("charge current %f", axp.getBattChargeCurrent());
LOG_DEBUG("bat voltage %f", axp.getBattVoltage());
LOG_DEBUG("batt pct %d", axp.getBattPercentage());
LOG_DEBUG("is battery connected %d", axp.isBatteryConnect());
LOG_DEBUG("is USB connected %d", axp.isVBUSPlug());
LOG_DEBUG("is charging %d", axp.isChargeing());
return 30 * 1000;
}
Periodic axpDebugOutput(axpDebugRead);
axpDebugOutput.setup();
#endif

View File

@@ -7,6 +7,7 @@
#include "PowerMon.h"
#include "RTC.h"
#include "Throttle.h"
#include "buzz.h"
#include "meshUtils.h"
#include "main.h" // pmu_found
@@ -19,6 +20,7 @@
#ifdef ARCH_PORTDUINO
#include "PortduinoGlue.h"
#include "meshUtils.h"
#include <algorithm>
#include <ctime>
#endif
@@ -154,7 +156,7 @@ uint8_t GPS::makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_siz
CASChecksum(UBXscratch, (payload_size + 10));
#if defined(GPS_DEBUG) && defined(DEBUG_PORT)
LOG_DEBUG("Constructed CAS packet: ");
LOG_DEBUG("CAS packet: ");
DEBUG_PORT.hexDump(MESHTASTIC_LOG_LEVEL_DEBUG, UBXscratch, payload_size + 10);
#endif
return (payload_size + 10);
@@ -235,7 +237,7 @@ GPS_RESPONSE GPS::getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMilli
// Check for an ACK-ACK for the specified class and message id
if ((msg_cls == 0x05) && (msg_msg_id == 0x01) && payload_cls == class_id && payload_msg == msg_id) {
#ifdef GPS_DEBUG
LOG_INFO("Got ACK for class %02X message %02X in %d millis.", class_id, msg_id, millis() - startTime);
LOG_INFO("Got ACK for class %02X message %02X in %dms", class_id, msg_id, millis() - startTime);
#endif
return GNSS_RESPONSE_OK;
}
@@ -243,7 +245,7 @@ GPS_RESPONSE GPS::getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMilli
// Check for an ACK-NACK for the specified class and message id
if ((msg_cls == 0x05) && (msg_msg_id == 0x00) && payload_cls == class_id && payload_msg == msg_id) {
#ifdef GPS_DEBUG
LOG_WARN("Got NACK for class %02X message %02X in %d millis.", class_id, msg_id, millis() - startTime);
LOG_WARN("Got NACK for class %02X message %02X in %dms", class_id, msg_id, millis() - startTime);
#endif
return GNSS_RESPONSE_NAK;
}
@@ -266,6 +268,9 @@ GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
uint32_t startTime = millis();
const char frame_errors[] = "More than 100 frame errors";
int sCounter = 0;
#ifdef GPS_DEBUG
std::string debugmsg = "";
#endif
for (int j = 2; j < 6; j++) {
buf[8] += buf[j];
@@ -281,8 +286,7 @@ GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
while (Throttle::isWithinTimespanMs(startTime, waitMillis)) {
if (ack > 9) {
#ifdef GPS_DEBUG
LOG_DEBUG("");
LOG_INFO("Got ACK for class %02X message %02X in %d millis.", class_id, msg_id, millis() - startTime);
LOG_INFO("Got ACK for class %02X message %02X in %dms", class_id, msg_id, millis() - startTime);
#endif
return GNSS_RESPONSE_OK; // ACK received
}
@@ -291,20 +295,24 @@ GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
if (b == frame_errors[sCounter]) {
sCounter++;
if (sCounter == 26) {
#ifdef GPS_DEBUG
LOG_DEBUG(debugmsg.c_str());
#endif
return GNSS_RESPONSE_FRAME_ERRORS;
}
} else {
sCounter = 0;
}
#ifdef GPS_DEBUG
LOG_DEBUG("%02X", b);
debugmsg += vformat("%02X", b);
#endif
if (b == buf[ack]) {
ack++;
} else {
if (ack == 3 && b == 0x00) { // UBX-ACK-NAK message
#ifdef GPS_DEBUG
LOG_DEBUG("");
LOG_DEBUG(debugmsg.c_str());
#endif
LOG_WARN("Got NAK for class %02X message %02X", class_id, msg_id);
return GNSS_RESPONSE_NAK; // NAK received
@@ -314,7 +322,7 @@ GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
}
}
#ifdef GPS_DEBUG
LOG_DEBUG("");
LOG_DEBUG(debugmsg.c_str());
LOG_WARN("No response for class %02X message %02X", class_id, msg_id);
#endif
return GNSS_RESPONSE_NONE; // No response received within timeout
@@ -388,8 +396,7 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
} else {
// return payload length
#ifdef GPS_DEBUG
LOG_INFO("Got ACK for class %02X message %02X in %d millis.", requestedClass, requestedID,
millis() - startTime);
LOG_INFO("Got ACK for class %02X message %02X in %dms", requestedClass, requestedID, millis() - startTime);
#endif
return needRead;
}
@@ -400,36 +407,49 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
}
}
}
// LOG_WARN("No response for class %02X message %02X", requestedClass, requestedID);
return 0;
}
/**
* @brief Setup the GPS based on the model detected.
* We detect the GPS by cycling through a set of baud rates, first common then rare.
* For each baud rate, we run GPS::Probe to send commands and match the responses
* to known GPS responses.
* @retval Whether setup reached the end of its potential to configure the GPS.
*/
bool GPS::setup()
{
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.
if (speedSelect == 0 && GPS_BAUDRATE != serialSpeeds[speedSelect]) {
speedSelect = std::find(serialSpeeds, std::end(serialSpeeds), GPS_BAUDRATE) - serialSpeeds;
if (probeTries < 2) {
LOG_DEBUG("Probe for GPS at %d", serialSpeeds[speedSelect]);
gnssModel = probe(serialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) {
if (++speedSelect == sizeof(serialSpeeds) / sizeof(int)) {
speedSelect = 0;
++probeTries;
}
}
}
LOG_DEBUG("Probing for GPS at %d", serialSpeeds[speedSelect]);
gnssModel = probe(serialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) {
if (++speedSelect == sizeof(serialSpeeds) / sizeof(int)) {
speedSelect = 0;
if (--probeTries == 0) {
LOG_WARN("Giving up on GPS probe and setting to 9600.");
// Rare Serial Speeds
if (probeTries == 2) {
LOG_DEBUG("Probe for GPS at %d", rareSerialSpeeds[speedSelect]);
gnssModel = probe(rareSerialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) {
if (++speedSelect == sizeof(rareSerialSpeeds) / sizeof(int)) {
LOG_WARN("Give up on GPS probe and set to %d", GPS_BAUDRATE);
return true;
}
}
return false;
}
}
if (gnssModel != GNSS_MODEL_UNKNOWN) {
setConnected();
} else {
gnssModel = GNSS_MODEL_UNKNOWN;
return false;
}
if (gnssModel == GNSS_MODEL_MTK) {
@@ -467,19 +487,31 @@ bool GPS::setup()
// Switch to Fitness Mode, for running and walking purpose with low speed (<5 m/s)
_serial_gps->write("$PMTK886,1*29\r\n");
delay(250);
} else if (gnssModel == GNSS_MODEL_MTK_PA1616S) {
// PA1616S is used in some GPS breakout boards from Adafruit
// PA1616S does not have GLONASS capability. PA1616D does, but is not implemented here.
_serial_gps->write("$PMTK353,1,0,0,0,0*2A\r\n");
// Above command will reset the GPS and takes longer before it will accept new commands
delay(1000);
// Only ask for RMC and GGA (GNRMC and GNGGA)
_serial_gps->write("$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n");
delay(250);
// Enable SBAS / WAAS
_serial_gps->write("$PMTK301,2*2E\r\n");
delay(250);
} else if (gnssModel == GNSS_MODEL_ATGM336H) {
// Set the intial configuration of the device - these _should_ work for most AT6558 devices
msglen = makeCASPacket(0x06, 0x07, sizeof(_message_CAS_CFG_NAVX_CONF), _message_CAS_CFG_NAVX_CONF);
_serial_gps->write(UBXscratch, msglen);
if (getACKCas(0x06, 0x07, 250) != GNSS_RESPONSE_OK) {
LOG_WARN("ATGM336H - Could not set Configuration");
LOG_WARN("ATGM336H: Could not set Config");
}
// Set the update frequence to 1Hz
msglen = makeCASPacket(0x06, 0x04, sizeof(_message_CAS_CFG_RATE_1HZ), _message_CAS_CFG_RATE_1HZ);
_serial_gps->write(UBXscratch, msglen);
if (getACKCas(0x06, 0x04, 250) != GNSS_RESPONSE_OK) {
LOG_WARN("ATGM336H - Could not set Update Frequency");
LOG_WARN("ATGM336H: Could not set Update Frequency");
}
// Set the NEMA output messages
@@ -491,7 +523,7 @@ bool GPS::setup()
msglen = makeCASPacket(0x06, 0x01, sizeof(cas_cfg_msg_packet), cas_cfg_msg_packet);
_serial_gps->write(UBXscratch, msglen);
if (getACKCas(0x06, 0x01, 250) != GNSS_RESPONSE_OK) {
LOG_WARN("ATGM336H - Could not enable NMEA MSG: %d", fields[i]);
LOG_WARN("ATGM336H: Could not enable NMEA MSG: %d", fields[i]);
}
}
} else if (gnssModel == GNSS_MODEL_UC6580) {
@@ -544,20 +576,20 @@ bool GPS::setup()
SEND_UBX_PACKET(0x06, 0x01, _message_GGA, "enable NMEA GGA", 500);
clearBuffer();
SEND_UBX_PACKET(0x06, 0x11, _message_CFG_RXM_ECO, "enable powersaving ECO mode for Neo-6", 500);
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "enable powersaving details for GPS", 500);
SEND_UBX_PACKET(0x06, 0x11, _message_CFG_RXM_ECO, "enable powersave ECO mode for Neo-6", 500);
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "enable powersave details for GPS", 500);
SEND_UBX_PACKET(0x06, 0x01, _message_AID, "disable UBX-AID", 500);
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.");
LOG_WARN("Unable to save GNSS module config");
} else {
LOG_INFO("GNSS module configuration saved!");
LOG_INFO("GNSS module config saved!");
}
} 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");
LOG_DEBUG("Set GPS+SBAS");
msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_7), _message_GNSS_7);
_serial_gps->write(UBXscratch, msglen);
} else { // 8,9
@@ -567,12 +599,12 @@ bool GPS::setup()
if (getACK(0x06, 0x3e, 800) == GNSS_RESPONSE_NAK) {
// It's not critical if the module doesn't acknowledge this configuration.
LOG_INFO("reconfigure GNSS - defaults maintained. Is this module GPS-only?");
LOG_DEBUG("reconfigure GNSS - defaults maintained. Is this module GPS-only?");
} else {
if (gnssModel == GNSS_MODEL_UBLOX7) {
LOG_INFO("GNSS configured for GPS+SBAS.");
LOG_INFO("GPS+SBAS configured");
} else { // 8,9
LOG_INFO("GNSS configured for GPS+SBAS+GLONASS+Galileo.");
LOG_INFO("GPS+SBAS+GLONASS+Galileo configured");
}
// 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 ;>)
@@ -604,8 +636,8 @@ bool GPS::setup()
if (uBloxProtocolVersion >= 18) {
clearBuffer();
SEND_UBX_PACKET(0x06, 0x86, _message_PMS, "enable powersaving for GPS", 500);
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "enable powersaving details for GPS", 500);
SEND_UBX_PACKET(0x06, 0x86, _message_PMS, "enable powersave for GPS", 500);
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "enable powersave details for GPS", 500);
// For M8 we want to enable NMEA vserion 4.10 so we can see the additional sats.
if (gnssModel == GNSS_MODEL_UBLOX8) {
@@ -613,14 +645,14 @@ bool GPS::setup()
SEND_UBX_PACKET(0x06, 0x17, _message_NMEA, "enable NMEA 4.10", 500);
}
} else {
SEND_UBX_PACKET(0x06, 0x11, _message_CFG_RXM_PSM, "enable powersaving mode for GPS", 500);
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "enable powersaving details for GPS", 500);
SEND_UBX_PACKET(0x06, 0x11, _message_CFG_RXM_PSM, "enable powersave mode for GPS", 500);
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "enable powersave details for GPS", 500);
}
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.");
LOG_WARN("Unable to save GNSS module config");
} else {
LOG_INFO("GNSS module configuration saved!");
}
@@ -640,13 +672,13 @@ bool GPS::setup()
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_TXT_INFO_BBR, "disable Info messages for M10 GPS BBR", 300);
delay(750);
// Do M10 configuration for Power Management.
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_PM_RAM, "enable powersaving for M10 GPS RAM", 300);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_PM_RAM, "enable powersave for M10 GPS RAM", 300);
delay(750);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_PM_BBR, "enable powersaving for M10 GPS BBR", 300);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_PM_BBR, "enable powersave for M10 GPS BBR", 300);
delay(750);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ITFM_RAM, "enable Jamming detection M10 GPS RAM", 300);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ITFM_RAM, "enable jam detection M10 GPS RAM", 300);
delay(750);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ITFM_BBR, "enable Jamming detection M10 GPS BBR", 300);
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ITFM_BBR, "enable jam detection M10 GPS BBR", 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, "disable SBAS M10 GPS RAM", 300);
@@ -654,7 +686,8 @@ bool GPS::setup()
SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_SBAS_BBR, "disable SBAS M10 GPS BBR", 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.
// 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, "enable messages for M10 GPS BBR", 300);
delay(750);
// Next enable wanted NMEA messages in RAM layer
@@ -667,7 +700,7 @@ bool GPS::setup()
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.");
LOG_WARN("Unable to save GNSS module config");
} else {
LOG_INFO("GNSS module configuration saved!");
}
@@ -691,7 +724,7 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
// Update the stored GPSPowerstate, and create local copies
GPSPowerState oldState = powerState;
powerState = newState;
LOG_INFO("GPS power state moving from %s to %s", getGPSPowerStateString(oldState), getGPSPowerStateString(newState));
LOG_INFO("GPS power state move from %s to %s", getGPSPowerStateString(oldState), getGPSPowerStateString(newState));
#ifdef HELTEC_MESH_NODE_T114
if ((oldState == GPS_OFF || oldState == GPS_HARDSLEEP) && (newState != GPS_OFF && newState != GPS_HARDSLEEP)) {
@@ -755,13 +788,14 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
void GPS::writePinEN(bool on)
{
// Abort: if conflict with Canned Messages when using Wisblock(?)
if (HW_VENDOR == meshtastic_HardwareModel_RAK4631 && (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1))
if ((HW_VENDOR == meshtastic_HardwareModel_RAK4631 || HW_VENDOR == meshtastic_HardwareModel_WISMESH_TAP) &&
(rotaryEncoderInterruptImpl1 || upDownInterruptImpl1))
return;
// Write and log
enablePin->set(on);
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("Pin EN %s", val == HIGH ? "HIGH" : "LOW");
#ifdef GPS_DEBUG
LOG_DEBUG("Pin EN %s", on == HIGH ? "HI" : "LOW");
#endif
}
@@ -782,8 +816,8 @@ void GPS::writePinStandby(bool standby)
// Write and log
pinMode(PIN_GPS_STANDBY, OUTPUT);
digitalWrite(PIN_GPS_STANDBY, val);
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("Pin STANDBY %s", val == HIGH ? "HIGH" : "LOW");
#ifdef GPS_DEBUG
LOG_DEBUG("Pin STANDBY %s", val == HIGH ? "HI" : "LOW");
#endif
#endif
}
@@ -815,8 +849,7 @@ void GPS::setPowerPMU(bool on)
// t-beam v1.1 GNSS power channel
on ? PMU->enablePowerOutput(XPOWERS_LDO3) : PMU->disablePowerOutput(XPOWERS_LDO3);
}
#ifdef GPS_EXTRAVERBOSE
#ifdef GPS_DEBUG
LOG_DEBUG("PMU %s", on ? "on" : "off");
#endif
#endif
@@ -833,9 +866,6 @@ void GPS::setPowerUBLOX(bool on, uint32_t sleepMs)
if (on) {
gps->_serial_gps->write(0xFF);
clearBuffer(); // This often returns old data, so drop it
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("UBLOX: wake");
#endif
}
// If putting to sleep
@@ -867,8 +897,7 @@ void GPS::setPowerUBLOX(bool on, uint32_t sleepMs)
// Send the UBX packet
gps->_serial_gps->write(gps->UBXscratch, msglen);
#ifdef GPS_EXTRAVERBOSE
#ifdef GPS_DEBUG
LOG_DEBUG("UBLOX: sleep for %dmS", sleepMs);
#endif
}
@@ -916,10 +945,10 @@ void GPS::down()
#endif
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
// 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
// improvement over a single, fixed threshold
uint32_t hardsleepThreshold = (2750 * pow(predictedSearchDuration / 1000, 1.22));
LOG_DEBUG("gps_update_interval >= %us needed to justify hardsleep", hardsleepThreshold / 1000);
@@ -940,8 +969,7 @@ void GPS::publishUpdate()
shouldPublish = false;
// In debug logs, identify position by @timestamp:stage (stage 2 = publish)
LOG_DEBUG("publishing pos@%x:2, hasVal=%d, Sats=%d, GPSlock=%d", p.timestamp, hasValidLocation, p.sats_in_view,
hasLock());
LOG_DEBUG("Publish pos@%x:2, hasVal=%d, Sats=%d, GPSlock=%d", p.timestamp, hasValidLocation, p.sats_in_view, hasLock());
// Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), isPowerSaving(), p);
@@ -956,7 +984,7 @@ int32_t GPS::runOnce()
{
if (!GPSInitFinished) {
if (!_serial_gps || config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) {
LOG_INFO("GPS set to not-present. Skipping probe.");
LOG_INFO("GPS set to not-present. Skip probe");
return disable();
}
if (!setup())
@@ -975,6 +1003,7 @@ int32_t GPS::runOnce()
}
}
GPSInitFinished = true;
publishUpdate();
}
// Repeaters have no need for GPS
@@ -991,7 +1020,7 @@ int32_t GPS::runOnce()
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.");
LOG_DEBUG("GPS is not found, try factory reset on next boot");
devicestate.did_gps_reset = false;
nodeDB->saveToDisk(SEGMENT_DEVICESTATE);
return disable(); // Stop the GPS thread as it can do nothing useful until next reboot.
@@ -1025,10 +1054,9 @@ int32_t GPS::runOnce()
bool tooLong = scheduling.searchedTooLong();
if (tooLong)
LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time.");
LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time");
// Once we get a location we no longer desperately want an update
// LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d", gotLoc, tooLong, gotTime);
if ((gotLoc && gotTime) || tooLong) {
if (tooLong) {
@@ -1094,7 +1122,7 @@ GnssModel_t GPS::probe(int serialSpeed)
_serial_gps->begin(serialSpeed);
#else
if (_serial_gps->baudRate() != serialSpeed) {
LOG_DEBUG("Setting Baud to %i", serialSpeed);
LOG_DEBUG("Set Baud to %i", serialSpeed);
_serial_gps->updateBaudRate(serialSpeed);
}
#endif
@@ -1135,6 +1163,7 @@ GnssModel_t GPS::probe(int serialSpeed)
delay(20);
PROBE_SIMPLE("L76B", "$PMTK605*31", "Quectel-L76B", GNSS_MODEL_MTK_L76B, 500);
PROBE_SIMPLE("PA1616S", "$PMTK605*31", "1616S", GNSS_MODEL_MTK_PA1616S, 500);
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
UBXChecksum(cfg_rate, sizeof(cfg_rate));
@@ -1143,7 +1172,7 @@ GnssModel_t GPS::probe(int serialSpeed)
// Check that the returned response class and message ID are correct
GPS_RESPONSE response = getACK(0x06, 0x08, 750);
if (response == GNSS_RESPONSE_NONE) {
LOG_WARN("Failed to find GNSS Module (baudrate %d)", serialSpeed);
LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed);
return GNSS_MODEL_UNKNOWN;
} else if (response == GNSS_RESPONSE_FRAME_ERRORS) {
LOG_INFO("UBlox Frame Errors (baudrate %d)", serialSpeed);
@@ -1163,7 +1192,6 @@ GnssModel_t GPS::probe(int serialSpeed)
uint16_t len = getACK(buffer, sizeof(buffer), 0x0A, 0x04, 1200);
if (len) {
// LOG_DEBUG("monver reply size = %d", len);
uint16_t position = 0;
for (int i = 0; i < 30; i++) {
info.swVersion[i] = buffer[position];
@@ -1228,7 +1256,7 @@ GnssModel_t GPS::probe(int serialSpeed)
return GNSS_MODEL_UBLOX10;
}
}
LOG_WARN("Failed to find GNSS Module (baudrate %d)", serialSpeed);
LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed);
return GNSS_MODEL_UNKNOWN;
}
@@ -1271,10 +1299,12 @@ GPS *GPS::createGps()
if (!GPS_EN_ACTIVE) { // Need to invert the pin before hardware
new GpioNotTransformer(
virtPin, p); // We just leave this created object on the heap so it can stay watching virtPin and driving en_gpio
virtPin,
p); // We just leave this created object on the heap so it can stay watching virtPin and driving en_gpio
} else {
new GpioUnaryTransformer(
virtPin, p); // We just leave this created object on the heap so it can stay watching virtPin and driving en_gpio
virtPin,
p); // We just leave this created object on the heap so it can stay watching virtPin and driving en_gpio
}
}
@@ -1289,7 +1319,7 @@ GPS *GPS::createGps()
// see NMEAGPS.h
gsafixtype.begin(reader, NMEA_MSG_GXGSA, 2);
gsapdop.begin(reader, NMEA_MSG_GXGSA, 15);
LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP");
LOG_DEBUG("Use " NMEA_MSG_GXGSA " for 3DFIX and PDOP");
#endif
// Make sure the GPS is awake before performing any init.
@@ -1310,8 +1340,8 @@ GPS *GPS::createGps()
// ESP32 has a special set of parameters vs other arduino ports
#if defined(ARCH_ESP32)
LOG_DEBUG("Using GPIO%d for GPS RX", new_gps->rx_gpio);
LOG_DEBUG("Using GPIO%d for GPS TX", new_gps->tx_gpio);
LOG_DEBUG("Use GPIO%d for GPS RX", new_gps->rx_gpio);
LOG_DEBUG("Use GPIO%d for GPS TX", 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);
@@ -1347,26 +1377,22 @@ bool GPS::factoryReset()
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xA2};
_serial_gps->write(_message_reset1, sizeof(_message_reset1));
if (getACK(0x05, 0x01, 10000)) {
LOG_INFO(ACK_SUCCESS_MESSAGE);
LOG_DEBUG(ACK_SUCCESS_MESSAGE);
}
delay(100);
byte _message_reset2[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1B, 0xA1};
_serial_gps->write(_message_reset2, sizeof(_message_reset2));
if (getACK(0x05, 0x01, 10000)) {
LOG_INFO(ACK_SUCCESS_MESSAGE);
LOG_DEBUG(ACK_SUCCESS_MESSAGE);
}
delay(100);
byte _message_reset3[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1D, 0xB3};
_serial_gps->write(_message_reset3, sizeof(_message_reset3));
if (getACK(0x05, 0x01, 10000)) {
LOG_INFO(ACK_SUCCESS_MESSAGE);
LOG_DEBUG(ACK_SUCCESS_MESSAGE);
}
// Reset device ram to COLDSTART state
// byte _message_CFG_RST_COLDSTART[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B};
// _serial_gps->write(_message_CFG_RST_COLDSTART, sizeof(_message_CFG_RST_COLDSTART));
// delay(1000);
} else if (gnssModel == GNSS_MODEL_MTK) {
// send the CAS10 to perform a factory restart of the device (and other device that support PCAS statements)
LOG_INFO("GNSS Factory Reset via PCAS10,3");
@@ -1382,8 +1408,8 @@ bool GPS::factoryReset()
_serial_gps->write("$PMTK104*37\r\n");
// No PMTK_ACK for this command.
delay(100);
// send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX.
// Factory Reset
// send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's
// UBLOX. Factory Reset
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
_serial_gps->write(_message_reset, sizeof(_message_reset));
@@ -1422,8 +1448,8 @@ bool GPS::lookForTime()
auto d = reader.date;
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
/* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1,
1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
struct tm t;
t.tm_sec = ti.second() + round(ti.age() / 1000);
@@ -1478,7 +1504,7 @@ bool GPS::lookForLocation()
#ifndef TINYGPS_OPTION_NO_STATISTICS
if (reader.failedChecksum() > lastChecksumFailCount) {
LOG_WARN("%u new GPS checksum failures, for a total of %u.", reader.failedChecksum() - lastChecksumFailCount,
LOG_WARN("%u new GPS checksum failures, for a total of %u", reader.failedChecksum() - lastChecksumFailCount,
reader.failedChecksum());
lastChecksumFailCount = reader.failedChecksum();
}
@@ -1486,14 +1512,13 @@ bool GPS::lookForLocation()
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
fixType = atoi(gsafixtype.value()); // will set to zero if no data
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d", fixQual, fixType);
#endif
// check if GPS has an acceptable lock
if (!hasLock())
return false;
#ifdef GPS_EXTRAVERBOSE
#ifdef GPS_DEBUG
LOG_DEBUG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d", reader.location.age(),
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
gsafixtype.age(),
@@ -1501,7 +1526,7 @@ bool GPS::lookForLocation()
0,
#endif
reader.date.age(), reader.time.age());
#endif // GPS_EXTRAVERBOSE
#endif // GPS_DEBUG
// Is this a new point or are we re-reading the previous one?
if (!reader.location.isUpdated() && !reader.altitude.isUpdated())
@@ -1524,13 +1549,13 @@ bool GPS::lookForLocation()
// Bail out EARLY to avoid overwriting previous good data (like #857)
if (toDegInt(loc.lat) > 900000000) {
#ifdef GPS_EXTRAVERBOSE
#ifdef GPS_DEBUG
LOG_DEBUG("Bail out EARLY on LAT %i", toDegInt(loc.lat));
#endif
return false;
}
if (toDegInt(loc.lng) > 1800000000) {
#ifdef GPS_EXTRAVERBOSE
#ifdef GPS_DEBUG
LOG_DEBUG("Bail out EARLY on LNG %i", toDegInt(loc.lng));
#endif
return false;
@@ -1542,7 +1567,6 @@ bool GPS::lookForLocation()
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
p.HDOP = reader.hdop.value();
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
// LOG_DEBUG("PDOP=%d, HDOP=%d", p.PDOP, p.HDOP);
#else
// FIXME! naive PDOP emulation (assumes VDOP==HDOP)
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)
@@ -1623,24 +1647,25 @@ bool GPS::whileActive()
{
unsigned int charsInBuf = 0;
bool isValid = false;
#ifdef GPS_DEBUG
std::string debugmsg = "";
#endif
if (powerState != GPS_ACTIVE) {
clearBuffer();
return false;
}
#ifdef SERIAL_BUFFER_SIZE
if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) {
LOG_WARN("GPS Buffer full with %u bytes waiting. Flushing to avoid corruption.", _serial_gps->available());
LOG_WARN("GPS Buffer full with %u bytes waiting. Flush to avoid corruption", _serial_gps->available());
clearBuffer();
}
#endif
// if (_serial_gps->available() > 0)
// LOG_DEBUG("GPS Bytes Waiting: %u", _serial_gps->available());
// First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) {
int c = _serial_gps->read();
UBXscratch[charsInBuf] = c;
#ifdef GPS_DEBUG
LOG_DEBUG("%c", c);
debugmsg += vformat("%c", (c >= 32 && c <= 126) ? c : '.');
#endif
isValid |= reader.encode(c);
if (charsInBuf > sizeof(UBXscratch) - 10 || c == '\r') {
@@ -1652,6 +1677,11 @@ bool GPS::whileActive()
charsInBuf++;
}
}
#ifdef GPS_DEBUG
if (debugmsg != "") {
LOG_DEBUG(debugmsg.c_str());
}
#endif
return isValid;
}
void GPS::enable()
@@ -1679,7 +1709,8 @@ void GPS::toggleGpsMode()
{
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
LOG_INFO("User toggled GpsMode. Now DISABLED.");
LOG_INFO("User toggled GpsMode. Now DISABLED");
playGPSDisableBeep();
#ifdef GNSS_AIROHA
if (powerState == GPS_ACTIVE) {
LOG_DEBUG("User power Off GPS");
@@ -1690,7 +1721,8 @@ void GPS::toggleGpsMode()
} else if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_DISABLED) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
LOG_INFO("User toggled GpsMode. Now ENABLED");
playGPSEnableBeep();
enable();
}
}
#endif // Exclude GPS
#endif // Exclude GPS

View File

@@ -34,6 +34,7 @@ typedef enum {
GNSS_MODEL_UC6580,
GNSS_MODEL_UNKNOWN,
GNSS_MODEL_MTK_L76B,
GNSS_MODEL_MTK_PA1616S,
GNSS_MODEL_AG3335,
GNSS_MODEL_AG3352
} GnssModel_t;
@@ -63,6 +64,95 @@ const char *getDOPString(uint32_t dop);
*/
class GPS : private concurrency::OSThread
{
public:
meshtastic_Position p = meshtastic_Position_init_default;
/** This is normally bound to config.position.gps_en_gpio but some rare boards (like heltec tracker) need more advanced
* implementations. Those boards will set this public variable to a custom implementation.
*
* Normally set by GPS::createGPS()
*/
GpioVirtPin *enablePin = NULL;
virtual ~GPS();
/** We will notify this observable anytime GPS state has changed meaningfully */
Observable<const meshtastic::GPSStatus *> newStatus;
/**
* Returns true if we succeeded
*/
virtual bool setup();
// re-enable the thread
void enable();
// Disable the thread
int32_t disable() override;
// toggle between enabled/disabled
void toggleGpsMode();
// Change the power state of the GPS - for power saving / shutdown
void setPowerState(GPSPowerState newState, uint32_t sleepMs = 0);
/// Returns true if we have acquired GPS lock.
virtual bool hasLock();
/// Returns true if there's valid data flow with the chip.
virtual bool hasFlow();
/// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; }
bool isPowerSaving() const { return config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED; }
// Empty the input buffer as quickly as possible
void clearBuffer();
virtual bool factoryReset();
// Creates an instance of the GPS class.
// Returns the new instance or null if the GPS is not present.
static GPS *createGps();
// Wake the GPS hardware - ready for an update
void up();
// Let the GPS hardware save power between updates
void down();
protected:
/// Record that we have a GPS
void setConnected();
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileActive();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation();
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
private:
GPS() : concurrency::OSThread("GPS") {}
TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA
uint32_t lastChecksumFailCount = 0;
@@ -74,14 +164,21 @@ class GPS : private concurrency::OSThread
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
uint8_t fixType = 0; // fix type from GPGSA
#endif
private:
const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600};
#if GPS_BAUDRATE_FIXED
// if GPS_BAUDRATE is specified in variant, only try that.
const int serialSpeeds[1] = {GPS_BAUDRATE};
const int rareSerialSpeeds[1] = {GPS_BAUDRATE};
#else
const int serialSpeeds[3] = {9600, 115200, 38400};
const int rareSerialSpeeds[3] = {4800, 57600, GPS_BAUDRATE};
#endif
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;
int speedSelect = 0;
int probeTries = 2;
int probeTries = 0;
/**
* hasValidLocation - indicates that the position variables contain a complete
@@ -104,7 +201,6 @@ class GPS : private concurrency::OSThread
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
public:
/** If !NULL we will use this serial port to construct our GPS */
#if defined(ARCH_RP2040)
static SerialUART *_serial_gps;
@@ -158,53 +254,6 @@ class GPS : private concurrency::OSThread
const char *ACK_SUCCESS_MESSAGE = "Get ack success!";
meshtastic_Position p = meshtastic_Position_init_default;
/** This is normally bound to config.position.gps_en_gpio but some rare boards (like heltec tracker) need more advanced
* implementations. Those boards will set this public variable to a custom implementation.
*
* Normally set by GPS::createGPS()
*/
GpioVirtPin *enablePin = NULL;
GPS() : concurrency::OSThread("GPS") {}
virtual ~GPS();
/** We will notify this observable anytime GPS state has changed meaningfully */
Observable<const meshtastic::GPSStatus *> newStatus;
/**
* Returns true if we succeeded
*/
virtual bool setup();
// re-enable the thread
void enable();
// Disable the thread
int32_t disable() override;
// toggle between enabled/disabled
void toggleGpsMode();
// Change the power state of the GPS - for power saving / shutdown
void setPowerState(GPSPowerState newState, uint32_t sleepMs = 0);
/// Returns true if we have acquired GPS lock.
virtual bool hasLock();
/// Returns true if there's valid data flow with the chip.
virtual bool hasFlow();
/// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; }
bool isPowerSaving() const { return config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED; }
// Empty the input buffer as quickly as possible
void clearBuffer();
// Create a ublox packet for editing in memory
uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
uint8_t makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
@@ -220,59 +269,6 @@ class GPS : private concurrency::OSThread
GPS_RESPONSE getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis);
virtual bool factoryReset();
// Creates an instance of the GPS class.
// Returns the new instance or null if the GPS is not present.
static GPS *createGps();
// Wake the GPS hardware - ready for an update
void up();
// Let the GPS hardware save power between updates
void down();
protected:
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
/// Record that we have a GPS
void setConnected();
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileActive();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation();
private:
/// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareDeepSleep(void *unused);
@@ -311,10 +307,7 @@ class GPS : private concurrency::OSThread
uint8_t fixeddelayCtr = 0;
const char *powerStateToString();
protected:
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
};
extern GPS *gps;
#endif // Exclude GPS
#endif // Exclude GPS

View File

@@ -49,7 +49,7 @@ uint32_t GPSUpdateScheduling::msUntilNextSearch()
}
// How long have we already been searching?
// Used to abort a search in progress, if it runs unnaceptably long
// Used to abort a search in progress, if it runs unacceptably long
uint32_t GPSUpdateScheduling::elapsedSearchMs()
{
// If searching
@@ -70,9 +70,9 @@ bool GPSUpdateScheduling::isUpdateDue()
// Have we been searching for a GPS position for too long?
bool GPSUpdateScheduling::searchedTooLong()
{
uint32_t maxSearchMs =
Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs);
uint32_t minimumOrConfiguredSecs =
Default::getConfiguredOrMinimumValue(config.position.position_broadcast_secs, default_broadcast_interval_secs);
uint32_t maxSearchMs = Default::getConfiguredOrDefaultMs(minimumOrConfiguredSecs, default_broadcast_interval_secs);
// If broadcast interval set to max, no such thing as "too long"
if (maxSearchMs == UINT32_MAX)
return false;
@@ -98,7 +98,7 @@ void GPSUpdateScheduling::updateLockTimePrediction()
// Ignore the first lock-time: likely to be long, will skew data
// Second locktime: likely stable. Use to intialize the smoothing filter
// Second locktime: likely stable. Use to initialize the smoothing filter
if (searchCount == 1)
predictedMsToGetLock = lockTime;
@@ -106,13 +106,13 @@ void GPSUpdateScheduling::updateLockTimePrediction()
else if (searchCount > 1)
predictedMsToGetLock = (lockTime * weighting) + (predictedMsToGetLock * (1 - weighting));
searchCount++; // Only tracked so we can diregard initial lock-times
searchCount++; // Only tracked so we can disregard initial lock-times
LOG_DEBUG("Predicting %us to get next lock", predictedMsToGetLock / 1000);
LOG_DEBUG("Predict %us to get next lock", predictedMsToGetLock / 1000);
}
// How long do we expect to spend searching for a lock?
uint32_t GPSUpdateScheduling::predictedSearchDurationMs()
{
return GPSUpdateScheduling::predictedMsToGetLock;
}
}

View File

@@ -23,7 +23,7 @@ uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_PositionLite &pos, c
{
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
char type = isCaltopoMode ? 'P' : 'N';
uint32_t len = snprintf(buf, bufsz, "$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(),
uint32_t len = snprintf(buf, bufsz, "\r\n$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(),
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(),
geoCoord.getDMSLonDeg(), (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
geoCoord.getDMSLonCP(), name);

View File

@@ -112,7 +112,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
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)!", printableEpoch, BUILD_EPOCH);
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
return false;
}
#endif
@@ -120,21 +120,21 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
bool shouldSet;
if (forceUpdate) {
shouldSet = true;
LOG_DEBUG("Overriding current RTC quality (%s) with incoming time of RTC quality of %s", RtcName(currentQuality),
LOG_DEBUG("Override current RTC quality (%s) with incoming time of RTC quality of %s", RtcName(currentQuality),
RtcName(q));
} else if (q > currentQuality) {
shouldSet = true;
LOG_DEBUG("Upgrading time to quality %s", RtcName(q));
LOG_DEBUG("Upgrade time to quality %s", RtcName(q));
} else if (q == RTCQualityGPS) {
shouldSet = true;
LOG_DEBUG("Reapplying GPS time: %ld secs", printableEpoch);
LOG_DEBUG("Reapply GPS time: %ld secs", 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", printableEpoch);
LOG_DEBUG("Reapply external time to correct clock drift %ld secs", printableEpoch);
} else {
shouldSet = false;
LOG_DEBUG("Current RTC quality: %s. Ignoring time of RTC quality of %s", RtcName(currentQuality), RtcName(q));
LOG_DEBUG("Current RTC quality: %s. Ignore time of RTC quality of %s", RtcName(currentQuality), RtcName(q));
}
if (shouldSet) {
@@ -230,7 +230,7 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
// LOG_DEBUG("Got time from GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
if (t.tm_year < 0 || t.tm_year >= 300) {
// LOG_DEBUG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
// LOG_DEBUG("Ignore invalid GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
return false;
} else {
return perhapsSetRTC(q, &tv);

View File

@@ -462,7 +462,7 @@ the PM config. Lets try without it.
PMREQ sort of works with SBAS, but the awake time is too short to re-acquire any SBAS sats.
The defination of "Got Fix" doesn't seem to include SBAS. Much more too this...
Even if it was, it can take minutes (up to 12.5),
even under good sat visability conditions to re-acquire the SBAS data.
even under good sat visibility conditions to re-acquire the SBAS data.
Another effect fo the quick transition to sleep is that no other sats will be acquired so the
sat count will tend to remain at what the initial fix was.

View File

@@ -79,7 +79,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
}
// Trigger the refresh in GxEPD2
LOG_DEBUG("Updating E-Paper");
LOG_DEBUG("Update E-Paper");
adafruitDisplay->nextPage();
// End the update process
@@ -123,7 +123,7 @@ void EInkDisplay::setDetected(uint8_t detected)
// Connect to the display - variant specific
bool EInkDisplay::connect()
{
LOG_INFO("Doing EInk init");
LOG_INFO("Do EInk init");
#ifdef PIN_EINK_EN
// backlight power, HIGH is backlight on, LOW is off

View File

@@ -119,7 +119,7 @@ void EInkDynamicDisplay::endOrDetach()
awaitRefresh();
else {
// Async begins
LOG_DEBUG("Async full-refresh begins (dropping frames)");
LOG_DEBUG("Async full-refresh begins (drop frames)");
notifyLater(intervalPollAsyncRefresh, DUE_POLL_ASYNCREFRESH, true); // Hand-off to NotifiedWorkerThread
}
}
@@ -170,7 +170,7 @@ bool EInkDynamicDisplay::determineMode()
checkFastRequested();
if (refresh == UNSPECIFIED)
LOG_WARN("There was a flaw in the determineMode() logic.");
LOG_WARN("There was a flaw in the determineMode() logic");
// -- Decision has been reached --
applyRefreshMode();
@@ -469,7 +469,7 @@ void EInkDynamicDisplay::joinAsyncRefresh()
if (!asyncRefreshRunning)
return;
LOG_DEBUG("Joining an async refresh in progress");
LOG_DEBUG("Join an async refresh in progress");
// Continually poll the BUSY pin
while (adafruitDisplay->epd2.isBusy())

View File

@@ -101,9 +101,9 @@ std::vector<MeshModule *> moduleFrames;
static char ourId[5];
// vector where symbols (string) are displayed in bottom corner of display.
std::vector<std::string> functionSymbals;
// string displayed in bottom right corner of display. Created from elements in functionSymbals vector
std::string functionSymbalString = "";
std::vector<std::string> functionSymbol;
// string displayed in bottom right corner of display. Created from elements in functionSymbol vector
std::string functionSymbolString = "";
#if HAS_GPS
// GeoCoord object for the screen
@@ -242,11 +242,11 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
// draw overlay in bottom right corner of screen to show when notifications are muted or modifier key is active
static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
{
// LOG_DEBUG("Drawing function overlay");
if (functionSymbals.begin() != functionSymbals.end()) {
// LOG_DEBUG("Draw function overlay");
if (functionSymbol.begin() != functionSymbol.end()) {
char buf[64];
display->setFont(FONT_SMALL);
snprintf(buf, sizeof(buf), "%s", functionSymbalString.c_str());
snprintf(buf, sizeof(buf), "%s", functionSymbolString.c_str());
display->drawString(SCREEN_WIDTH - display->getStringWidth(buf), SCREEN_HEIGHT - FONT_HEIGHT_SMALL, buf);
}
}
@@ -260,7 +260,7 @@ static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state,
EINK_ADD_FRAMEFLAG(display, COSMETIC);
EINK_ADD_FRAMEFLAG(display, BLOCKING);
LOG_DEBUG("Drawing deep sleep screen");
LOG_DEBUG("Draw deep sleep screen");
// Display displayStr on the screen
drawIconScreen("Sleeping", display, state, x, y);
@@ -269,7 +269,7 @@ static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state,
/// Used on eink displays when screen updates are paused
static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
{
LOG_DEBUG("Drawing screensaver overlay");
LOG_DEBUG("Draw screensaver overlay");
EINK_ADD_FRAMEFLAG(display, COSMETIC); // Take the opportunity for a full-refresh
@@ -337,7 +337,7 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
module_frame = state->currentFrame;
// LOG_DEBUG("Screen is not in transition. Frame: %d", module_frame);
}
// LOG_DEBUG("Drawing Module Frame %d", module_frame);
// LOG_DEBUG("Draw Module Frame %d", module_frame);
MeshModule &pi = *moduleFrames.at(module_frame);
pi.drawFrame(display, state, x, y);
}
@@ -396,7 +396,7 @@ static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *img
display->drawFastImage(x, y, 16, 8, imgBuffer);
}
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
void Screen::drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode, float scale)
{
@@ -912,7 +912,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
const meshtastic_MeshPacket &mp = devicestate.rx_text_message;
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
// LOG_DEBUG("drawing text message from 0x%x: %s", mp.from,
// LOG_DEBUG("Draw text message from 0x%x: %s", mp.from,
// mp.decoded.variant.data.decoded.bytes);
// Demo for drawStringMaxWidth:
@@ -958,55 +958,65 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
display->setColor(WHITE);
#ifndef EXCLUDE_EMOJI
if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F44D") == 0) {
const char *msg = reinterpret_cast<const char *>(mp.decoded.payload.bytes);
if (strcmp(msg, "\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), "\U0001F44E") == 0) {
} else if (strcmp(msg, "\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), "") == 0) {
} else if (strcmp(msg, "\U0001F60A") == 0 || strcmp(msg, "\U0001F600") == 0 || strcmp(msg, "\U0001F642") == 0 ||
strcmp(msg, "\U0001F609") == 0 ||
strcmp(msg, "\U0001F601") == 0) { // matches 5 different common smileys, so that the phone user doesn't have to
// remember which one is compatible
display->drawXbm(x + (SCREEN_WIDTH - smiley_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - smiley_height) / 2 + 2 + 5, smiley_width, smiley_height,
smiley);
} else if (strcmp(msg, "") == 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), "‼️") == 0) {
} else if (strcmp(msg, "‼️") == 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), "\U0001F4A9") == 0) {
} else if (strcmp(msg, "\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) {
} else if (strcmp(msg, "\U0001F923") == 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), "\U0001F44B") == 0) {
} else if (strcmp(msg, "\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), "\U0001F920") == 0) {
} else if (strcmp(msg, "\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), "\U0001F42D") == 0) {
} else if (strcmp(msg, "\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), "\xE2\x98\x80\xEF\xB8\x8F") == 0) {
} else if (strcmp(msg, "\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), "\u2614") == 0) {
} else if (strcmp(msg, "\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), "☁️") == 0) {
} else if (strcmp(msg, "☁️") == 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), "🌫️") == 0) {
} else if (strcmp(msg, "🌫️") == 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), "\xf0\x9f\x98\x88") == 0) {
} else if (strcmp(msg, "\U0001F608") == 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), "♥️") == 0) {
} else if (strcmp(msg, "♥️") == 0 || strcmp(msg, "\U0001F9E1") == 0 || strcmp(msg, "\U00002763") == 0 ||
strcmp(msg, "\U00002764") == 0 || strcmp(msg, "\U0001F495") == 0 || strcmp(msg, "\U0001F496") == 0 ||
strcmp(msg, "\U0001F497") == 0 || strcmp(msg, "\U0001F496") == 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 {
@@ -1499,7 +1509,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
#elif ARCH_PORTDUINO
if (settingsMap[displayPanel] != no_screen) {
LOG_DEBUG("Making TFTDisplay!");
LOG_DEBUG("Make TFTDisplay!");
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
} else {
@@ -1546,7 +1556,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
if (on != screenOn) {
if (on) {
LOG_INFO("Turning on screen");
LOG_INFO("Turn on screen");
powerMon->setState(meshtastic_PowerMon_State_Screen_On);
#ifdef T_WATCH_S3
PMU->enablePowerOutput(XPOWERS_ALDO2);
@@ -1581,7 +1591,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
// eInkScreensaver parameter is usually NULL (default argument), default frame used instead
setScreensaverFrames(einkScreensaver);
#endif
LOG_INFO("Turning off screen");
LOG_INFO("Turn off screen");
dispdev->displayOff();
#ifdef USE_ST7789
SPI1.end();
@@ -1789,7 +1799,7 @@ int32_t Screen::runOnce()
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
static bool showingBootScreen = true;
if (showingBootScreen && (millis() > (logo_timeout + serialSinceMsec))) {
LOG_INFO("Done with boot screen...");
LOG_INFO("Done with boot screen");
stopBootScreen();
showingBootScreen = false;
}
@@ -1885,7 +1895,7 @@ int32_t Screen::runOnce()
EINK_ADD_FRAMEFLAG(dispdev, COSMETIC);
#endif
LOG_DEBUG("LastScreenTransition exceeded %ums transitioning to next frame", (millis() - lastScreenTransition));
LOG_DEBUG("LastScreenTransition exceeded %ums transition to next frame", (millis() - lastScreenTransition));
handleOnPress();
}
}
@@ -1921,7 +1931,7 @@ void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiStat
void Screen::setSSLFrames()
{
if (address_found.address) {
// LOG_DEBUG("showing SSL frames");
// LOG_DEBUG("Show SSL frames");
static FrameCallback sslFrames[] = {drawSSLScreen};
ui->setFrames(sslFrames, 1);
ui->update();
@@ -1933,7 +1943,7 @@ void Screen::setSSLFrames()
void Screen::setWelcomeFrames()
{
if (address_found.address) {
// LOG_DEBUG("showing Welcome frames");
// LOG_DEBUG("Show Welcome frames");
static FrameCallback frames[] = {drawWelcomeScreen};
setFrameImmediateDraw(frames);
}
@@ -1999,7 +2009,7 @@ void Screen::setFrames(FrameFocus focus)
uint8_t originalPosition = ui->getUiState()->currentFrame;
FramesetInfo fsi; // Location of specific frames, for applying focus parameter
LOG_DEBUG("showing standard frames");
LOG_DEBUG("Show standard frames");
showingNormalScreen = true;
#ifdef USE_EINK
@@ -2012,7 +2022,7 @@ void Screen::setFrames(FrameFocus focus)
#endif
moduleFrames = MeshModule::GetMeshModulesWithUIFrames();
LOG_DEBUG("Showing %d module frames", moduleFrames.size());
LOG_DEBUG("Show %d module frames", moduleFrames.size());
#ifdef DEBUG_PORT
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.size();
LOG_DEBUG("Total frame count: %d", totalFrameCount);
@@ -2058,7 +2068,7 @@ void Screen::setFrames(FrameFocus focus)
focus = FOCUS_FAULT; // Change our "focus" parameter, to ensure we show the fault frame
}
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
normalFrames[numframes++] = screen->digitalWatchFace ? &Screen::drawDigitalClockFrame : &Screen::drawAnalogClockFrame;
#endif
@@ -2094,7 +2104,7 @@ void Screen::setFrames(FrameFocus focus)
#endif
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
LOG_DEBUG("Finished building frames. numframes: %d", numframes);
LOG_DEBUG("Finished build frames. numframes: %d", numframes);
ui->setFrames(normalFrames, numframes);
ui->enableAllIndicators();
@@ -2175,13 +2185,13 @@ void Screen::dismissCurrentFrame()
bool dismissed = false;
if (currentFrame == framesetInfo.positions.textMessage && devicestate.has_rx_text_message) {
LOG_INFO("Dismissing Text Message");
LOG_INFO("Dismiss Text Message");
devicestate.has_rx_text_message = false;
dismissed = true;
}
else if (currentFrame == framesetInfo.positions.waypoint && devicestate.has_rx_waypoint) {
LOG_DEBUG("Dismissing Waypoint");
LOG_DEBUG("Dismiss Waypoint");
devicestate.has_rx_waypoint = false;
dismissed = true;
}
@@ -2193,7 +2203,7 @@ void Screen::dismissCurrentFrame()
void Screen::handleStartFirmwareUpdateScreen()
{
LOG_DEBUG("showing firmware screen");
LOG_DEBUG("Show firmware screen");
showingNormalScreen = false;
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame
@@ -2242,24 +2252,24 @@ void Screen::decreaseBrightness()
/* TO DO: add little popup in center of screen saying what brightness level it is set to*/
}
void Screen::setFunctionSymbal(std::string sym)
void Screen::setFunctionSymbol(std::string sym)
{
if (std::find(functionSymbals.begin(), functionSymbals.end(), sym) == functionSymbals.end()) {
functionSymbals.push_back(sym);
functionSymbalString = "";
for (auto symbol : functionSymbals) {
functionSymbalString = symbol + " " + functionSymbalString;
if (std::find(functionSymbol.begin(), functionSymbol.end(), sym) == functionSymbol.end()) {
functionSymbol.push_back(sym);
functionSymbolString = "";
for (auto symbol : functionSymbol) {
functionSymbolString = symbol + " " + functionSymbolString;
}
setFastFramerate();
}
}
void Screen::removeFunctionSymbal(std::string sym)
void Screen::removeFunctionSymbol(std::string sym)
{
functionSymbals.erase(std::remove(functionSymbals.begin(), functionSymbals.end(), sym), functionSymbals.end());
functionSymbalString = "";
for (auto symbol : functionSymbals) {
functionSymbalString = symbol + " " + functionSymbalString;
functionSymbol.erase(std::remove(functionSymbol.begin(), functionSymbol.end(), sym), functionSymbol.end());
functionSymbolString = "";
for (auto symbol : functionSymbol) {
functionSymbolString = symbol + " " + functionSymbolString;
}
setFastFramerate();
}
@@ -2674,7 +2684,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET)
setFrames(FOCUS_MODULE);
// Regenerate the frameset, while attempting to maintain focus on the current frame
// Regenerate the frameset, while Attempt to maintain focus on the current frame
else if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET_BACKGROUND)
setFrames(FOCUS_PRESERVE);
@@ -2689,7 +2699,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
int Screen::handleInputEvent(const InputEvent *event)
{
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
// For the T-Watch, intercept touches to the 'toggle digital/analog watch face' button
uint8_t watchFaceFrame = error_code ? 1 : 0;
@@ -2747,4 +2757,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg)
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
#endif // HAS_SCREEN
#endif // HAS_SCREEN

View File

@@ -24,8 +24,8 @@ class Screen
void startFirmwareUpdateScreen() {}
void increaseBrightness() {}
void decreaseBrightness() {}
void setFunctionSymbal(std::string) {}
void removeFunctionSymbal(std::string) {}
void setFunctionSymbol(std::string) {}
void removeFunctionSymbol(std::string) {}
void startAlert(const char *) {}
void endAlert() {}
};
@@ -282,8 +282,8 @@ class Screen : public concurrency::OSThread
void increaseBrightness();
void decreaseBrightness();
void setFunctionSymbal(std::string sym);
void removeFunctionSymbal(std::string sym);
void setFunctionSymbol(std::string sym);
void removeFunctionSymbol(std::string sym);
/// Stops showing the boot screen.
void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); }
@@ -327,10 +327,15 @@ class Screen : public concurrency::OSThread
SKIPREST = false;
return (uint8_t)ch;
}
case 0xC3: {
SKIPREST = false;
return (uint8_t)(ch | 0xC0);
}
}
// We want to strip out prefix chars for two-byte char formats
if (ch == 0xC2)
if (ch == 0xC2 || ch == 0xC3)
return (uint8_t)0;
#if defined(OLED_PL)
@@ -549,7 +554,7 @@ class Screen : public concurrency::OSThread
static void drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
static void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
static void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
@@ -600,4 +605,4 @@ class Screen : public concurrency::OSThread
} // namespace graphics
#endif
#endif

View File

@@ -823,7 +823,7 @@ void TFTDisplay::setDetected(uint8_t detected)
bool TFTDisplay::connect()
{
concurrency::LockGuard g(spiLock);
LOG_INFO("Doing TFT init");
LOG_INFO("Do TFT init");
#ifdef RAK14014
tft = new TFT_eSPI;
#else

View File

@@ -14,7 +14,7 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0xe3, 0x1f,
0xf3, 0x3f, 0x33, 0x30, 0x33, 0x33, 0x33, 0x33, 0x03, 0x33, 0xff, 0x33,
0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
@@ -56,6 +56,16 @@ static unsigned char thumbdown[] PROGMEM = {
0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
};
#define smiley_height 30
#define smiley_width 30
static unsigned char smiley[] PROGMEM = {
0x00, 0xfe, 0x0f, 0x00, 0x80, 0x01, 0x30, 0x00, 0x40, 0x00, 0xc0, 0x00, 0x20, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x02,
0x08, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x10, 0x02, 0x0e, 0x0e, 0x10, 0x02, 0x09, 0x12, 0x10,
0x01, 0x09, 0x12, 0x20, 0x01, 0x0f, 0x1e, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20,
0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x81, 0x00, 0x20, 0x20,
0x82, 0x00, 0x20, 0x10, 0x02, 0x01, 0x10, 0x10, 0x04, 0x02, 0x08, 0x08, 0x04, 0xfc, 0x07, 0x08, 0x08, 0x00, 0x00, 0x04,
0x10, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0xc0, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0xfe, 0x0f, 0x00};
#define question_height 25
#define question_width 25
static unsigned char question[] PROGMEM = {

View File

@@ -0,0 +1,430 @@
// Based on the BBQ10 Keyboard
#include "MPR121Keyboard.h"
#include "configuration.h"
#include <Arduino.h>
#define _MPR121_REG_KEY 0x5a
#define _MPR121_REG_TOUCH_STATUS 0x00
#define _MPR121_REG_ELECTRODE_FILTERED_DATA
#define _MPR121_REG_BASELINE_VALUE 0x1E
// Baseline filters
#define _MPR121_REG_MAX_HALF_DELTA_RISING 0x2B
#define _MPR121_REG_NOISE_HALF_DELTA_RISING 0x2C
#define _MPR121_REG_NOISE_COUNT_LIMIT_RISING 0x2D
#define _MPR121_REG_FILTER_DELAY_COUNT_RISING 0x2E
#define _MPR121_REG_MAX_HALF_DELTA_FALLING 0x2F
#define _MPR121_REG_NOISE_HALF_DELTA_FALLING 0x30
#define _MPR121_REG_NOISE_COUNT_LIMIT_FALLING 0x31
#define _MPR121_REG_FILTER_DELAY_COUNT_FALLING 0x32
#define _MPR121_REG_NOISE_HALF_DELTA_TOUCHED 0x33
#define _MPR121_REG_NOISE_COUNT_LIMIT_TOUCHED 0x34
#define _MPR121_REG_FILTER_DELAY_COUNT_TOUCHED 0x35
#define _MPR121_REG_TOUCH_THRESHOLD 0x41 // First input, +2 for subsequent
#define _MPR121_REG_RELEASE_THRESHOLD 0x42 // First input, +2 for subsequent
#define _MPR121_REG_DEBOUNCE 0x5B
#define _MPR121_REG_CONFIG1 0x5C
#define _MPR121_REG_CONFIG2 0x5D
#define _MPR121_REG_ELECTRODE_CONFIG 0x5E
#define _MPR121_REG_SOFT_RESET 0x80
#define _KEY_MASK 0x0FFF // Key mask for the first 12 bits
#define _NUM_KEYS 12
#define ECR_CALIBRATION_TRACK_FROM_ZERO (0 << 6)
#define ECR_CALIBRATION_LOCK (1 << 6)
#define ECR_CALIBRATION_TRACK_FROM_PARTIAL_FILTER (2 << 6) // Recommended Typical Mode
#define ECR_CALIBRATION_TRACK_FROM_FULL_FILTER (3 << 6)
#define ECR_PROXIMITY_DETECTION_OFF (0 << 0) // Not using proximity detection
#define ECR_TOUCH_DETECTION_12CH (12 << 0) // Using all 12 channels
#define MPR121_NONE 0x00
#define MPR121_REBOOT 0x90
#define MPR121_LEFT 0xb4
#define MPR121_UP 0xb5
#define MPR121_DOWN 0xb6
#define MPR121_RIGHT 0xb7
#define MPR121_ESC 0x1b
#define MPR121_BSP 0x08
#define MPR121_SELECT 0x0d
#define MPR121_FN_ON 0xf1
#define MPR121_FN_OFF 0xf2
#define LONG_PRESS_THRESHOLD 2000
#define MULTI_TAP_THRESHOLD 2000
uint8_t TapMod[12] = {1, 2, 1, 13, 7, 7, 7, 7, 7, 9, 7, 9}; // Num chars per key, Modulus for rotating through characters
unsigned char MPR121_TapMap[12][13] = {{MPR121_BSP},
{'0', ' '},
{MPR121_SELECT},
{'1', '.', ',', '?', '!', ':', ';', '-', '_', '\\', '/', '(', ')'},
{'2', 'a', 'b', 'c', 'A', 'B', 'C'},
{'3', 'd', 'e', 'f', 'D', 'E', 'F'},
{'4', 'g', 'h', 'i', 'G', 'H', 'I'},
{'5', 'j', 'k', 'l', 'J', 'K', 'L'},
{'6', 'm', 'n', 'o', 'M', 'N', 'O'},
{'7', 'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S'},
{'8', 't', 'u', 'v', 'T', 'U', 'V'},
{'9', 'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z'}};
unsigned char MPR121_LongPressMap[12] = {MPR121_ESC, ' ', MPR121_NONE, MPR121_NONE, MPR121_UP, MPR121_NONE,
MPR121_LEFT, MPR121_NONE, MPR121_RIGHT, MPR121_NONE, MPR121_DOWN, MPR121_NONE};
// Translation map from left to right, top to bottom layout to a more convenient layout to manufacture, matching the
// https://www.amazon.com.au/Capacitive-Sensitive-Sensitivity-Replacement-Traditional/dp/B0CTJD5KW9/ref=pd_ci_mcx_mh_mcx_views_0_title?th=1
/*uint8_t MPR121_KeyMap[12] = {
9, 6, 3, 0,
10, 7, 4, 1,
11, 8, 5, 2
};*/
// Rotated Layout
uint8_t MPR121_KeyMap[12] = {2, 5, 8, 11, 1, 4, 7, 10, 0, 3, 6, 9};
MPR121Keyboard::MPR121Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr)
{
// LOG_DEBUG("MPR121 @ %02x\n", m_addr);
state = Init;
last_key = -1;
last_tap = 0L;
char_idx = 0;
queue = "";
}
void MPR121Keyboard::begin(uint8_t addr, TwoWire *wire)
{
m_addr = addr;
m_wire = wire;
m_wire->begin();
reset();
}
void MPR121Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
{
m_addr = addr;
m_wire = nullptr;
writeCallback = w;
readCallback = r;
reset();
}
void MPR121Keyboard::reset()
{
LOG_DEBUG("MPR121 Reset");
// Trigger a MPR121 Soft Reset
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(_MPR121_REG_SOFT_RESET);
m_wire->endTransmission();
}
if (writeCallback) {
uint8_t data = 0;
writeCallback(m_addr, _MPR121_REG_SOFT_RESET, &data, 0);
}
delay(100);
// Reset Electrode Configuration to 0x00, Stop Mode
writeRegister(_MPR121_REG_ELECTRODE_CONFIG, 0x00);
delay(100);
LOG_DEBUG("MPR121 Configure");
// Set touch release thresholds
for (uint8_t i = 0; i < 12; i++) {
// Set touch threshold
writeRegister(_MPR121_REG_TOUCH_THRESHOLD + (i * 2), 15);
delay(20);
// Set release threshold
writeRegister(_MPR121_REG_RELEASE_THRESHOLD + (i * 2), 7);
delay(20);
}
// Configure filtering and baseline registers
writeRegister(_MPR121_REG_MAX_HALF_DELTA_RISING, 0x01);
delay(20);
writeRegister(_MPR121_REG_MAX_HALF_DELTA_FALLING, 0x01);
delay(20);
writeRegister(_MPR121_REG_NOISE_HALF_DELTA_RISING, 0x01);
delay(20);
writeRegister(_MPR121_REG_NOISE_HALF_DELTA_FALLING, 0x05);
delay(20);
writeRegister(_MPR121_REG_NOISE_HALF_DELTA_TOUCHED, 0x00);
delay(20);
writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_RISING, 0x0e);
delay(20);
writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_FALLING, 0x01);
delay(20);
writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_TOUCHED, 0x00);
delay(20);
writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_RISING, 0x00);
delay(20);
writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_FALLING, 0x00);
delay(20);
writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_TOUCHED, 0x00);
delay(20);
// Set Debounce to 0x02
writeRegister(_MPR121_REG_DEBOUNCE, 0x00);
delay(20);
// Set Filter1 itterations and discharge current 6x and 16uA respectively (0x10)
writeRegister(_MPR121_REG_CONFIG1, 0x10);
delay(20);
// Set CDT to 0.5us, Filter2 itterations to 4x, and Sample interval = 0 (0x20)
writeRegister(_MPR121_REG_CONFIG2, 0x20);
delay(20);
// Enter run mode by Seting partial filter calibration tracking, disable proximity detection, enable 12 channels
writeRegister(_MPR121_REG_ELECTRODE_CONFIG,
ECR_CALIBRATION_TRACK_FROM_PARTIAL_FILTER | ECR_PROXIMITY_DETECTION_OFF | ECR_TOUCH_DETECTION_12CH);
delay(100);
LOG_DEBUG("MPR121 Run");
state = Idle;
}
void MPR121Keyboard::attachInterrupt(uint8_t pin, void (*func)(void)) const
{
pinMode(pin, INPUT_PULLUP);
::attachInterrupt(digitalPinToInterrupt(pin), func, RISING);
}
void MPR121Keyboard::detachInterrupt(uint8_t pin) const
{
::detachInterrupt(pin);
}
uint8_t MPR121Keyboard::status() const
{
return readRegister16(_MPR121_REG_KEY);
}
uint8_t MPR121Keyboard::keyCount() const
{
// Read the key register
uint16_t keyRegister = readRegister16(_MPR121_REG_KEY);
return keyCount(keyRegister);
}
uint8_t MPR121Keyboard::keyCount(uint16_t value) const
{
// Mask the first 12 bits
uint16_t buttonState = value & _KEY_MASK;
// Count how many bits are set to 1 (i.e., how many buttons are pressed)
uint8_t numButtonsPressed = 0;
for (uint8_t i = 0; i < 12; ++i) {
if (buttonState & (1 << i)) {
numButtonsPressed++;
}
}
return numButtonsPressed;
}
bool MPR121Keyboard::hasEvent()
{
return queue.length() > 0;
}
void MPR121Keyboard::queueEvent(char next)
{
if (next == MPR121_NONE) {
return;
}
queue.concat(next);
}
char MPR121Keyboard::dequeueEvent()
{
if (queue.length() < 1) {
return MPR121_NONE;
}
char next = queue.charAt(0);
queue.remove(0, 1);
return next;
}
void MPR121Keyboard::trigger()
{
// Intended to fire in response to an interrupt from the MPR121 or a longpress callback
// Only functional if not in Init state
if (state != Init) {
// Read the key register
uint16_t keyRegister = readRegister16(_MPR121_REG_KEY);
uint8_t keysPressed = keyCount(keyRegister);
if (keysPressed == 0) {
// No buttons pressed
if (state == Held)
released();
state = Idle;
return;
}
if (keysPressed == 1) {
// No buttons pressed
if (state == Held || state == HeldLong)
held(keyRegister);
if (state == Idle)
pressed(keyRegister);
return;
}
if (keysPressed > 1) {
// Multipress
state = Busy;
return;
}
} else {
reset();
}
}
void MPR121Keyboard::pressed(uint16_t keyRegister)
{
if (state == Init || state == Busy) {
return;
}
if (keyCount(keyRegister) != 1) {
LOG_DEBUG("Multipress");
return;
} else {
LOG_DEBUG("Pressed");
}
uint16_t buttonState = keyRegister & _KEY_MASK;
uint8_t next_pin = 0;
for (uint8_t i = 0; i < 12; ++i) {
if (buttonState & (1 << i)) {
next_pin = i;
}
}
uint8_t next_key = MPR121_KeyMap[next_pin];
LOG_DEBUG("MPR121 Pin: %i Key: %i", next_pin, next_key);
uint32_t now = millis();
int32_t tap_interval = now - last_tap;
if (tap_interval < 0) {
// long running, millis has overflowed.
last_tap = 0;
state = Busy;
return;
}
if (next_key != last_key || tap_interval > MULTI_TAP_THRESHOLD) {
char_idx = 0;
} else {
char_idx += 1;
}
last_key = next_key;
last_tap = now;
state = Held;
return;
}
void MPR121Keyboard::held(uint16_t keyRegister)
{
if (state == Init || state == Busy) {
return;
}
if (keyCount(keyRegister) != 1) {
return;
}
LOG_DEBUG("Held");
uint16_t buttonState = keyRegister & _KEY_MASK;
uint8_t next_key = 0;
for (uint8_t i = 0; i < 12; ++i) {
if (buttonState & (1 << i)) {
next_key = MPR121_KeyMap[i];
}
}
uint32_t now = millis();
int32_t held_interval = now - last_tap;
if (held_interval < 0 || next_key != last_key) {
// long running, millis has overflowed, or a key has been switched quickly...
last_tap = 0;
state = Busy;
return;
}
if (held_interval > LONG_PRESS_THRESHOLD) {
// Set state to heldlong, send a longpress, and reset the timer...
state = HeldLong; // heldlong will allow this function to still fire, but prevent a "release"
queueEvent(MPR121_LongPressMap[last_key]);
last_tap = now;
LOG_DEBUG("Long Press Key: %i Map: %i", last_key, MPR121_LongPressMap[last_key]);
}
return;
}
void MPR121Keyboard::released()
{
if (state != Held) {
return;
}
// would clear longpress callback... later.
if (last_key < 0 || last_key > _NUM_KEYS) { // reset to idle if last_key out of bounds
last_key = -1;
state = Idle;
return;
}
LOG_DEBUG("Released");
if (char_idx > 0 && TapMod[last_key] > 1) {
queueEvent(MPR121_BSP);
LOG_DEBUG("Multi Press, Backspace");
}
queueEvent(MPR121_TapMap[last_key][(char_idx % TapMod[last_key])]);
LOG_DEBUG("Key Press: %i Index:%i if %i Map: %i", last_key, char_idx, TapMod[last_key],
MPR121_TapMap[last_key][(char_idx % TapMod[last_key])]);
}
uint8_t MPR121Keyboard::readRegister8(uint8_t reg) const
{
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, (uint8_t)1);
if (m_wire->available() < 1)
return 0;
return m_wire->read();
}
if (readCallback) {
uint8_t data;
readCallback(m_addr, reg, &data, 1);
return data;
}
return 0;
}
uint16_t MPR121Keyboard::readRegister16(uint8_t reg) const
{
uint8_t data[2] = {0};
// uint8_t low = 0, high = 0;
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, (uint8_t)2);
if (m_wire->available() < 2)
return 0;
data[0] = m_wire->read();
data[1] = m_wire->read();
}
if (readCallback) {
readCallback(m_addr, reg, data, 2);
}
return (data[1] << 8) | data[0];
}
void MPR121Keyboard::writeRegister(uint8_t reg, uint8_t value)
{
uint8_t data[2];
data[0] = reg;
data[1] = value;
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(data, sizeof(uint8_t) * 2);
m_wire->endTransmission();
}
if (writeCallback) {
writeCallback(m_addr, data[0], &(data[1]), 1);
}
}

View File

@@ -0,0 +1,56 @@
// Based on the BBQ10 Keyboard
#include "concurrency/NotifiedWorkerThread.h"
#include "configuration.h"
#include <Wire.h>
#include <main.h>
class MPR121Keyboard
{
public:
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
enum MPR121States { Init = 0, Idle, Held, HeldLong, Busy };
MPR121States state;
int8_t last_key;
uint32_t last_tap;
uint8_t char_idx;
String queue;
MPR121Keyboard();
void begin(uint8_t addr = MPR121_KB_ADDR, TwoWire *wire = &Wire);
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = MPR121_KB_ADDR);
void reset(void);
void attachInterrupt(uint8_t pin, void (*func)(void)) const;
void detachInterrupt(uint8_t pin) const;
void trigger(void);
void pressed(uint16_t value);
void held(uint16_t value);
void released(void);
uint8_t status(void) const;
uint8_t keyCount(void) const;
uint8_t keyCount(uint16_t value) const;
bool hasEvent(void);
char dequeueEvent(void);
void queueEvent(char);
uint8_t readRegister8(uint8_t reg) const;
uint16_t readRegister16(uint8_t reg) const;
void writeRegister(uint8_t reg, uint8_t value);
private:
TwoWire *m_wire;
uint8_t m_addr;
i2c_com_fptr_t readCallback;
i2c_com_fptr_t writeCallback;
};

View File

@@ -59,7 +59,7 @@ int32_t ScanAndSelectInput::runOnce()
// If: "no messages added" alert screen currently shown
if (alertingNoMessage) {
// Dismiss the alert screen several seconds after it appears
if (now > alertingSinceMs + durationAlertMs) {
if (!Throttle::isWithinTimespanMs(alertingSinceMs, durationAlertMs)) {
alertingNoMessage = false;
screen->endAlert();
}
@@ -74,9 +74,9 @@ int32_t ScanAndSelectInput::runOnce()
// Existing press
else {
// Duration enough for long press
// Longer than shortpress window
// Long press not yet fired (prevent repeat firing while held)
if (!longPressFired && Throttle::isWithinTimespanMs(downSinceMs, durationLongMs)) {
if (!longPressFired && !Throttle::isWithinTimespanMs(downSinceMs, durationLongMs)) {
longPressFired = true;
longPress();
}
@@ -91,7 +91,9 @@ int32_t ScanAndSelectInput::runOnce()
// Button newly released
// Long press event didn't already fire
if (held && !longPressFired) {
// Duration enough for short press
// Duration within shortpress window
// - longer than durationShortPress (debounce)
// - shorter than durationLongPress
if (!Throttle::isWithinTimespanMs(downSinceMs, durationShortMs)) {
shortPress();
}

View File

@@ -1,6 +1,10 @@
#include "TouchScreenBase.h"
#include "main.h"
#if defined(RAK14014) && !defined(MESHTASTIC_EXCLUDE_CANNEDMESSAGES)
#include "modules/CannedMessageModule.h"
#endif
#ifndef TIME_LONG_PRESS
#define TIME_LONG_PRESS 400
#endif
@@ -102,12 +106,30 @@ int32_t TouchScreenBase::runOnce()
}
_touchedOld = touched;
#if defined RAK14014
// Speed up the processing speed of the keyboard in virtual keyboard mode
auto state = cannedMessageModule->getRunState();
if (state == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
if (_tapped) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y);
}
} else {
if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y);
}
}
#else
// fire TAP event when no 2nd tap occured within time
if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
LOG_DEBUG("action TAP(%d/%d)", _last_x, _last_y);
}
#endif
// fire LONG_PRESS event without the need for release
if (touched && (time_t(millis()) - _start) > TIME_LONG_PRESS) {

View File

@@ -9,11 +9,11 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
void CardKbI2cImpl::init()
{
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO)
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(I2C_NO_RESCAN)
if (cardkb_found.address == 0x00) {
LOG_DEBUG("Rescanning for I2C keyboard");
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR};
uint8_t i2caddr_asize = 3;
LOG_DEBUG("Rescan for I2C keyboard");
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR};
uint8_t i2caddr_asize = 4;
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
#if WIRE_INTERFACES_COUNT == 2
@@ -39,12 +39,17 @@ void CardKbI2cImpl::init()
// assign an arbitrary value to distinguish from other models
kb_model = 0x11;
break;
case ScanI2C::DeviceType::MPR121KB:
// assign an arbitrary value to distinguish from other models
kb_model = 0x37;
break;
default:
// use this as default since it's also just zero
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);
kb_model = 0x00;
}
}
LOG_DEBUG("Keyboard Type: 0x%02x Model: 0x%02x Address: 0x%02x", kb_info.type, kb_model, cardkb_found.address);
if (cardkb_found.address == 0x00) {
disable();
return;

View File

@@ -34,21 +34,27 @@ int32_t KbI2cBase::runOnce()
switch (cardkb_found.port) {
case ScanI2C::WIRE1:
#if WIRE_INTERFACES_COUNT == 2
LOG_DEBUG("Using I2C Bus 1 (the second one)");
LOG_DEBUG("Use I2C Bus 1 (the second one)");
i2cBus = &Wire1;
if (cardkb_found.address == BBQ10_KB_ADDR) {
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire1);
Q10keyboard.setBacklight(0);
}
if (cardkb_found.address == MPR121_KB_ADDR) {
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire1);
}
break;
#endif
case ScanI2C::WIRE:
LOG_DEBUG("Using I2C Bus 0 (the first one)");
LOG_DEBUG("Use I2C Bus 0 (the first one)");
i2cBus = &Wire;
if (cardkb_found.address == BBQ10_KB_ADDR) {
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire);
Q10keyboard.setBacklight(0);
}
if (cardkb_found.address == MPR121_KB_ADDR) {
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire);
}
break;
case ScanI2C::NO_I2C:
default:
@@ -157,6 +163,69 @@ int32_t KbI2cBase::runOnce()
}
break;
}
case 0x37: { // MPR121
MPRkeyboard.trigger();
InputEvent e;
while (MPRkeyboard.hasEvent()) {
char nextEvent = MPRkeyboard.dequeueEvent();
e.inputEvent = ANYKEY;
e.kbchar = 0x00;
e.source = this->_originName;
switch (nextEvent) {
case 0x00: // MPR121_NONE
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.kbchar = 0x00;
break;
case 0x90: // MPR121_REBOOT
e.inputEvent = ANYKEY;
e.kbchar = INPUT_BROKER_MSG_REBOOT;
break;
case 0xb4: // MPR121_LEFT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = 0x00;
break;
case 0xb5: // MPR121_UP
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.kbchar = 0x00;
break;
case 0xb6: // MPR121_DOWN
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.kbchar = 0x00;
break;
case 0xb7: // MPR121_RIGHT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = 0x00;
break;
case 0x1b: // MPR121_ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.kbchar = 0x1b;
break;
case 0x08: // MPR121_BSP
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.kbchar = 0x08;
break;
case 0x0d: // MPR121_SELECT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.kbchar = 0x0d;
break;
default:
if (nextEvent > 127) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.kbchar = 0x00;
break;
}
e.inputEvent = ANYKEY;
e.kbchar = nextEvent;
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
LOG_DEBUG("MP121 Notifying: %i Char: %i", e.inputEvent, e.kbchar);
this->notifyObservers(&e);
}
}
break;
}
case 0x02: {
// RAK14004
uint8_t rDataBuf[8] = {0};

View File

@@ -2,6 +2,7 @@
#include "BBQ10Keyboard.h"
#include "InputBroker.h"
#include "MPR121Keyboard.h"
#include "Wire.h"
#include "concurrency/OSThread.h"
@@ -19,5 +20,6 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
TwoWire *i2cBus = 0;
BBQ10Keyboard Q10keyboard;
MPR121Keyboard MPRkeyboard;
bool is_sym = false;
};
};

View File

@@ -27,7 +27,6 @@
#include "detect/ScanI2CTwoWire.h"
#include <Wire.h>
#endif
#include "detect/axpDebug.h"
#include "detect/einkScan.h"
#include "graphics/RAKled.h"
#include "graphics/Screen.h"
@@ -267,14 +266,19 @@ void setup()
#ifdef DEBUG_PORT
consoleInit(); // Set serial baud rate and init our mesh console
#endif
#ifdef UNPHONE
unphone.printStore();
#endif
#if ARCH_PORTDUINO
struct timeval tv;
tv.tv_sec = time(NULL);
tv.tv_usec = 0;
perhapsSetRTC(RTCQualityNTP, &tv);
#endif
powerMonInit();
powerMonInit();
serialSinceMsec = millis();
LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n");
@@ -324,7 +328,7 @@ void setup()
#ifdef PERIPHERAL_WARMUP_MS
// Some peripherals may require additional time to stabilize after power is connected
// e.g. I2C on Heltec Vision Master
LOG_INFO("Waiting for peripherals to stabilize");
LOG_INFO("Wait for peripherals to stabilize");
delay(PERIPHERAL_WARMUP_MS);
#endif
@@ -385,10 +389,10 @@ void setup()
Wire.begin(I2C_SDA, I2C_SCL);
#elif defined(ARCH_PORTDUINO)
if (settingsStrings[i2cdev] != "") {
LOG_INFO("Using %s as I2C device.", settingsStrings[i2cdev].c_str());
LOG_INFO("Use %s as I2C device", settingsStrings[i2cdev].c_str());
Wire.begin(settingsStrings[i2cdev].c_str());
} else {
LOG_INFO("No I2C device configured, skipping.");
LOG_INFO("No I2C device configured, Skip");
}
#elif HAS_WIRE
Wire.begin();
@@ -431,7 +435,7 @@ void setup()
// accessories
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
#if HAS_WIRE
LOG_INFO("Scanning for i2c devices...");
LOG_INFO("Scan for i2c devices");
#endif
#if defined(I2C_SDA1) && defined(ARCH_RP2040)
@@ -456,7 +460,7 @@ void setup()
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#elif defined(ARCH_PORTDUINO)
if (settingsStrings[i2cdev] != "") {
LOG_INFO("Scanning for i2c devices...");
LOG_INFO("Scan for i2c devices");
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
}
#elif HAS_WIRE
@@ -523,6 +527,10 @@ void setup()
// assign an arbitrary value to distinguish from other models
kb_model = 0x11;
break;
case ScanI2C::DeviceType::MPR121KB:
// assign an arbitrary value to distinguish from other models
kb_model = 0x37;
break;
default:
// use this as default since it's also just zero
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);
@@ -639,6 +647,8 @@ void setup()
rp2040Setup();
#endif
initSPI(); // needed here before reading from littleFS
// We do this as early as possible because this loads preferences from flash
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
nodeDB = new NodeDB;
@@ -661,7 +671,7 @@ void setup()
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");
LOG_DEBUG("Tracker/Sensor: Skip start melody");
else
playStartMelody();
@@ -702,7 +712,6 @@ void setup()
#endif
// Init our SPI controller (must be before screen and lora)
initSPI();
#ifdef ARCH_RP2040
#ifdef HW_SPI1_DEVICE
SPI1.setSCK(LORA_SCK);
@@ -731,7 +740,7 @@ void setup()
// setup TZ prior to time actions.
#if !MESHTASTIC_EXCLUDE_TZ
LOG_DEBUG("Using compiled/slipstreamed %s", slipstreamTZString); // important, removing this clobbers our magic string
LOG_DEBUG("Use compiled/slipstreamed %s", slipstreamTZString); // important, removing this clobbers our magic string
if (*config.device.tzdef && config.device.tzdef[0] != 0) {
LOG_DEBUG("Saved TZ: %s ", config.device.tzdef);
setenv("TZ", config.device.tzdef, 1);
@@ -761,7 +770,7 @@ void setup()
if (gps) {
gpsStatus->observe(&gps->newStatus);
} else {
LOG_DEBUG("Running without GPS.");
LOG_DEBUG("Run without GPS");
}
}
}
@@ -774,7 +783,7 @@ void setup()
nodeStatus->observe(&nodeDB->newStatus);
#ifdef HAS_I2S
LOG_DEBUG("Starting audio thread");
LOG_DEBUG("Start audio thread");
audioThread = new AudioThread();
#endif
service = new MeshService();
@@ -821,63 +830,63 @@ void setup()
#ifdef ARCH_PORTDUINO
if (settingsMap[use_sx1262]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1262 radio on SPI port %s", settingsStrings[spidev].c_str());
LOG_DEBUG("Activate sx1262 radio on SPI port %s", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL =
new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC));
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
LOG_ERROR("Failed to find SX1262 radio");
LOG_WARN("No SX1262 radio");
delete rIf;
exit(EXIT_FAILURE);
} else {
LOG_INFO("SX1262 Radio init succeeded, using SX1262 radio");
LOG_INFO("SX1262 init success");
}
}
} else if (settingsMap[use_rf95]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate rf95 radio on SPI port %s", settingsStrings[spidev].c_str());
LOG_DEBUG("Activate rf95 radio on SPI port %s", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL =
new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC));
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
LOG_ERROR("Failed to find RF95 radio");
LOG_WARN("No RF95 radio");
delete rIf;
rIf = NULL;
exit(EXIT_FAILURE);
} else {
LOG_INFO("RF95 Radio init succeeded, using RF95 radio");
LOG_INFO("RF95 init success");
}
}
} else if (settingsMap[use_sx1280]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1280 radio on SPI port %s", settingsStrings[spidev].c_str());
LOG_DEBUG("Activate sx1280 radio on SPI port %s", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
LOG_ERROR("Failed to find SX1280 radio");
LOG_WARN("No SX1280 radio");
delete rIf;
rIf = NULL;
exit(EXIT_FAILURE);
} else {
LOG_INFO("SX1280 Radio init succeeded, using SX1280 radio");
LOG_INFO("SX1280 init success");
}
}
} else if (settingsMap[use_sx1268]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1268 radio on SPI port %s", settingsStrings[spidev].c_str());
LOG_DEBUG("Activate sx1268 radio on SPI port %s", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
LOG_ERROR("Failed to find SX1268 radio");
LOG_WARN("No SX1268 radio");
delete rIf;
rIf = NULL;
exit(EXIT_FAILURE);
} else {
LOG_INFO("SX1268 Radio init succeeded, using SX1268 radio");
LOG_INFO("SX1268 init success");
}
}
}
@@ -893,11 +902,11 @@ void setup()
if (!rIf) {
rIf = new STM32WLE5JCInterface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find STM32WL radio");
LOG_WARN("No STM32WL radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("STM32WL Radio init succeeded, using STM32WL radio");
LOG_INFO("STM32WL init success");
radioType = STM32WLx_RADIO;
}
}
@@ -907,11 +916,11 @@ void setup()
if (!rIf) {
rIf = new SimRadio;
if (!rIf->init()) {
LOG_WARN("Failed to find simulated radio");
LOG_WARN("No simulated radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("Using SIMULATED radio!");
LOG_INFO("Use SIMULATED radio!");
radioType = SIM_RADIO;
}
}
@@ -921,11 +930,11 @@ void setup()
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");
LOG_WARN("No RF95 radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("RF95 Radio init succeeded, using RF95 radio");
LOG_INFO("RF95 init success");
radioType = RF95_RADIO;
}
}
@@ -935,11 +944,11 @@ void setup()
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");
LOG_WARN("No SX1262 radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("SX1262 Radio init succeeded, using SX1262 radio");
LOG_INFO("SX1262 init success");
radioType = SX1262_RADIO;
}
}
@@ -950,12 +959,12 @@ void setup()
// Try using the specified TCXO voltage
rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find SX1262 radio with TCXO, Vref %f V", tcxoVoltage);
LOG_WARN("No SX1262 radio with TCXO, Vref %f V", tcxoVoltage);
delete rIf;
rIf = NULL;
tcxoVoltage = 0; // if it fails, set the TCXO voltage to zero for the next attempt
} else {
LOG_WARN("SX1262 Radio init succeeded, TCXO, Vref %f V", tcxoVoltage);
LOG_WARN("SX1262 init success, TCXO, Vref %f V", tcxoVoltage);
radioType = SX1262_RADIO;
}
}
@@ -964,12 +973,12 @@ void setup()
// 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()) {
LOG_WARN("Failed to find SX1262 radio with XTAL, Vref %f V", tcxoVoltage);
LOG_WARN("No SX1262 radio with XTAL, Vref %f V", tcxoVoltage);
delete rIf;
rIf = NULL;
tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE; // if it fails, set the TCXO voltage back for the next radio search
} else {
LOG_INFO("SX1262 Radio init succeeded, XTAL, Vref %f V", tcxoVoltage);
LOG_INFO("SX1262 init success, XTAL, Vref %f V", tcxoVoltage);
radioType = SX1262_RADIO;
}
}
@@ -979,11 +988,11 @@ void setup()
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");
LOG_WARN("No SX1268 radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("SX1268 Radio init succeeded, using SX1268 radio");
LOG_INFO("SX1268 init success");
radioType = SX1268_RADIO;
}
}
@@ -993,11 +1002,11 @@ void setup()
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");
LOG_WARN("No LLCC68 radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("LLCC68 Radio init succeeded, using LLCC68 radio");
LOG_INFO("LLCC68 init success");
radioType = LLCC68_RADIO;
}
}
@@ -1007,11 +1016,11 @@ void setup()
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");
LOG_WARN("No LR1110 radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("LR1110 Radio init succeeded, using LR1110 radio");
LOG_INFO("LR1110 init success");
radioType = LR1110_RADIO;
}
}
@@ -1021,11 +1030,11 @@ void setup()
if (!rIf) {
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");
LOG_WARN("No LR1120 radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("LR1120 Radio init succeeded, using LR1120 radio");
LOG_INFO("LR1120 init success");
radioType = LR1120_RADIO;
}
}
@@ -1035,11 +1044,11 @@ void setup()
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");
LOG_WARN("No LR1121 radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("LR1121 Radio init succeeded, using LR1121 radio");
LOG_INFO("LR1121 init success");
radioType = LR1121_RADIO;
}
}
@@ -1049,11 +1058,11 @@ void setup()
if (!rIf) {
rIf = new SX1280Interface(RadioLibHAL, SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find SX1280 radio");
LOG_WARN("No SX1280 radio");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("SX1280 Radio init succeeded, using SX1280 radio");
LOG_INFO("SX1280 init success");
radioType = SX1280_RADIO;
}
}
@@ -1061,7 +1070,7 @@ void setup()
// 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.");
LOG_WARN("LoRa chip does not support 2.4GHz. Revert to unset");
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
nodeDB->saveToDisk(SEGMENT_CONFIG);
if (!rIf->reconfigure()) {
@@ -1151,6 +1160,32 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
deviceMetadata.position_flags = config.position.position_flags;
deviceMetadata.hw_model = HW_VENDOR;
deviceMetadata.hasRemoteHardware = moduleConfig.remote_hardware.enabled;
deviceMetadata.excluded_modules = meshtastic_ExcludedModules_EXCLUDED_NONE;
#if MESHTASTIC_EXCLUDE_REMOTEHARDWARE
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_REMOTEHARDWARE_CONFIG;
#endif
#if MESHTASTIC_EXCLUDE_AUDIO
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_AUDIO_CONFIG;
#endif
#if !HAS_SCREEN || NO_EXT_GPIO
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_CANNEDMSG_CONFIG | meshtastic_ExcludedModules_EXTNOTIF_CONFIG;
#endif
// Only edge case here is if we apply this a device with built in Accelerometer and want to detect interrupts
// We'll have to macro guard against those targets potentially
#if NO_EXT_GPIO
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_DETECTIONSENSOR_CONFIG;
#endif
// If we don't have any GPIO and we don't have GPS, no purpose in having serial config
#if NO_EXT_GPIO && NO_GPS
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_SERIAL_CONFIG;
#endif
#ifndef ARCH_ESP32
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_PAXCOUNTER_CONFIG;
#endif
#if !defined(HAS_NCP5623) && !defined(RGBLED_RED) && !defined(HAS_NEOPIXEL) && !defined(UNPHONE) && !RAK_4631
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_AMBIENTLIGHTING_CONFIG;
#endif
#if !(MESHTASTIC_EXCLUDE_PKI)
deviceMetadata.hasPKC = true;
#endif
@@ -1186,4 +1221,4 @@ void loop()
mainDelay.delay(delayMsec);
}
}
#endif
#endif

View File

@@ -117,13 +117,18 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
static const uint8_t defaultpsk0[] = USERPREFS_CHANNEL_0_PSK;
memcpy(channelSettings.psk.bytes, defaultpsk0, sizeof(defaultpsk0));
channelSettings.psk.size = sizeof(defaultpsk0);
#endif
#ifdef USERPREFS_CHANNEL_0_NAME
strcpy(channelSettings.name, USERPREFS_CHANNEL_0_NAME);
#endif
#ifdef USERPREFS_CHANNEL_0_PRECISION
channelSettings.module_settings.position_precision = USERPREFS_CHANNEL_0_PRECISION;
#endif
#ifdef USERPREFS_CHANNEL_0_UPLINK_ENABLED
channelSettings.uplink_enabled = USERPREFS_CHANNEL_0_UPLINK_ENABLED;
#endif
#ifdef USERPREFS_CHANNEL_0_DOWNLINK_ENABLED
channelSettings.downlink_enabled = USERPREFS_CHANNEL_0_DOWNLINK_ENABLED;
#endif
break;
case 1:
@@ -131,13 +136,18 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
static const uint8_t defaultpsk1[] = USERPREFS_CHANNEL_1_PSK;
memcpy(channelSettings.psk.bytes, defaultpsk1, sizeof(defaultpsk1));
channelSettings.psk.size = sizeof(defaultpsk1);
#endif
#ifdef USERPREFS_CHANNEL_1_NAME
strcpy(channelSettings.name, USERPREFS_CHANNEL_1_NAME);
#endif
#ifdef USERPREFS_CHANNEL_1_PRECISION
channelSettings.module_settings.position_precision = USERPREFS_CHANNEL_1_PRECISION;
#endif
#ifdef USERPREFS_CHANNEL_1_UPLINK_ENABLED
channelSettings.uplink_enabled = USERPREFS_CHANNEL_1_UPLINK_ENABLED;
#endif
#ifdef USERPREFS_CHANNEL_1_DOWNLINK_ENABLED
channelSettings.downlink_enabled = USERPREFS_CHANNEL_1_DOWNLINK_ENABLED;
#endif
break;
case 2:
@@ -145,13 +155,18 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
static const uint8_t defaultpsk2[] = USERPREFS_CHANNEL_2_PSK;
memcpy(channelSettings.psk.bytes, defaultpsk2, sizeof(defaultpsk2));
channelSettings.psk.size = sizeof(defaultpsk2);
#endif
#ifdef USERPREFS_CHANNEL_2_NAME
strcpy(channelSettings.name, USERPREFS_CHANNEL_2_NAME);
#endif
#ifdef USERPREFS_CHANNEL_2_PRECISION
channelSettings.module_settings.position_precision = USERPREFS_CHANNEL_2_PRECISION;
#endif
#ifdef USERPREFS_CHANNEL_2_UPLINK_ENABLED
channelSettings.uplink_enabled = USERPREFS_CHANNEL_2_UPLINK_ENABLED;
#endif
#ifdef USERPREFS_CHANNEL_2_DOWNLINK_ENABLED
channelSettings.downlink_enabled = USERPREFS_CHANNEL_2_DOWNLINK_ENABLED;
#endif
break;
default:
@@ -175,7 +190,7 @@ CryptoKey Channels::getKey(ChannelIndex chIndex)
k.length = channelSettings.psk.size;
if (k.length == 0) {
if (ch.role == meshtastic_Channel_Role_SECONDARY) {
LOG_DEBUG("Unset PSK for secondary channel %s. using primary key", ch.settings.name);
LOG_DEBUG("Unset PSK for secondary channel %s. use primary key", ch.settings.name);
k = getKey(primaryIndex);
} else {
LOG_WARN("User disabled encryption");
@@ -184,7 +199,7 @@ CryptoKey Channels::getKey(ChannelIndex chIndex)
// Convert the short single byte variants of psk into variant that can be used more generally
uint8_t pskIndex = k.bytes[0];
LOG_DEBUG("Expanding short PSK #%d", pskIndex);
LOG_DEBUG("Expand short PSK #%d", pskIndex);
if (pskIndex == 0)
k.length = 0; // Turn off encryption
else {
@@ -369,11 +384,11 @@ bool Channels::hasDefaultChannel()
bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
{
if (chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
// LOG_DEBUG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x", chIndex, getHash(chIndex),
// LOG_DEBUG("Skip channel %d (hash %x) due to invalid hash/index, want=%x", chIndex, getHash(chIndex),
// channelHash);
return false;
} else {
LOG_DEBUG("Using channel %d (hash 0x%x)", chIndex, channelHash);
LOG_DEBUG("Use channel %d (hash 0x%x)", chIndex, channelHash);
setCrypto(chIndex);
return true;
}
@@ -383,7 +398,7 @@ bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
*
* This method is called before encoding outbound packets
*
* @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
* @return the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
*/
int16_t Channels::setActiveByIndex(ChannelIndex channelIndex)
{

View File

@@ -18,7 +18,7 @@
*/
void CryptoEngine::generateKeyPair(uint8_t *pubKey, uint8_t *privKey)
{
LOG_DEBUG("Generating Curve25519 key pair...");
LOG_DEBUG("Generate Curve25519 keypair");
Curve25519::dh1(public_key, private_key);
memcpy(pubKey, public_key, sizeof(public_key));
memcpy(privKey, private_key, sizeof(private_key));
@@ -80,8 +80,8 @@ bool CryptoEngine::encryptCurve25519(uint32_t toNode, uint32_t fromNode, meshtas
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 starting with: ", shared_key, 8);
printBytes("Attempt encrypt with nonce: ", nonce, 13);
printBytes("Attempt encrypt with 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
memcpy((uint8_t *)(auth + 8), &extraNonceTmp,
@@ -117,8 +117,8 @@ bool CryptoEngine::decryptCurve25519(uint32_t fromNode, meshtastic_UserLite_publ
crypto->hash(shared_key, 32);
initNonce(fromNode, packetNum, extraNonce);
printBytes("Attempting decrypt using nonce: ", nonce, 13);
printBytes("Attempting decrypt using shared_key starting with: ", shared_key, 8);
printBytes("Attempt decrypt with nonce: ", nonce, 13);
printBytes("Attempt decrypt with shared_key starting with: ", shared_key, 8);
return aes_ccm_ad(shared_key, 32, nonce, 8, bytes, numBytes - 12, nullptr, 0, auth, bytesOut);
}
@@ -185,7 +185,7 @@ concurrency::Lock *cryptLock;
void CryptoEngine::setKey(const CryptoKey &k)
{
LOG_DEBUG("Using AES%d key!", k.length * 8);
LOG_DEBUG("Use AES%d key!", k.length * 8);
key = k;
}
@@ -249,4 +249,4 @@ void CryptoEngine::initNonce(uint32_t fromNode, uint64_t packetId, uint32_t extr
}
#ifndef HAS_CUSTOM_CRYPTO_ENGINE
CryptoEngine *crypto = new CryptoEngine;
#endif
#endif

View File

@@ -1,5 +1,6 @@
#include "Default.h"
#include "../userPrefs.h"
#include "meshUtils.h"
uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval)
{
@@ -40,9 +41,22 @@ uint32_t Default::getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t d
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER)
return getConfiguredOrDefaultMs(configured, defaultValue);
// Additionally if we're a tracker or sensor, we want priority to send position and telemetry
if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_SENSOR, meshtastic_Config_DeviceConfig_Role_TRACKER))
return getConfiguredOrDefaultMs(configured, defaultValue);
return getConfiguredOrDefaultMs(configured, defaultValue) * congestionScalingCoefficient(numOnlineNodes);
}
uint32_t Default::getConfiguredOrMinimumValue(uint32_t configured, uint32_t minValue)
{
// If zero, intervals should be coalesced later by getConfiguredOrDefault... methods
if (configured == 0)
return configured;
return configured < minValue ? minValue : configured;
}
uint8_t Default::getConfiguredOrDefaultHopLimit(uint8_t configured)
{
#if USERPREFS_EVENT_MODE

View File

@@ -1,13 +1,15 @@
#pragma once
#include <NodeDB.h>
#include <cstdint>
#include <meshUtils.h>
#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 min_default_telemetry_interval_secs 30 * 60
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 30 * 60)
#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 60 * 60)
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
#define default_wait_bluetooth_secs IF_ROUTER(1, 60)
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep
@@ -17,7 +19,7 @@
#define default_node_info_broadcast_secs 3 * 60 * 60
#define default_neighbor_info_broadcast_secs 6 * 60 * 60
#define min_node_info_broadcast_secs 60 * 60 // No regular broadcasts of more than once an hour
#define min_neighbor_info_broadcast_secs 2 * 60 * 60
#define min_neighbor_info_broadcast_secs 4 * 60 * 60
#define default_mqtt_address "mqtt.meshtastic.org"
#define default_mqtt_username "meshdev"
@@ -35,16 +37,35 @@ class Default
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
static uint32_t getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes);
static uint8_t getConfiguredOrDefaultHopLimit(uint8_t configured);
static uint32_t getConfiguredOrMinimumValue(uint32_t configured, uint32_t minValue);
private:
static float congestionScalingCoefficient(int numOnlineNodes)
{
if (numOnlineNodes <= 40) {
return 1.0; // No scaling for 40 or fewer nodes
// Increase frequency of broadcasts for small networks regardless of preset
if (numOnlineNodes <= 10) {
return 0.6;
} else if (numOnlineNodes <= 20) {
return 0.7;
} else if (numOnlineNodes <= 30) {
return 0.8;
} else if (numOnlineNodes <= 40) {
return 1.0;
} else {
// Sscaling based on number of nodes over 40
float throttlingFactor = 0.075;
if (config.lora.use_preset && config.lora.modem_preset == meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW)
throttlingFactor = 0.04;
else if (config.lora.use_preset && config.lora.modem_preset == meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST)
throttlingFactor = 0.02;
else if (config.lora.use_preset && config.lora.modem_preset == meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW)
throttlingFactor = 0.01;
else if (config.lora.use_preset &&
IS_ONE_OF(config.lora.modem_preset, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST,
meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO))
return 1.0; // Don't bother throttling for highest bandwidth presets
// Scaling up traffic based on number of nodes over 40
int nodesOverForty = (numOnlineNodes - 40);
return 1.0 + (nodesOverForty * 0.075); // Each number of online node scales by 0.075
return 1.0 + (nodesOverForty * throttlingFactor); // Each number of online node scales by 0.075 (default)
}
}
};

View File

@@ -21,7 +21,7 @@ ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p)
bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
{
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
printPacket("Ignoring dupe incoming msg", p);
printPacket("Ignore dupe incoming msg", p);
rxDupe++;
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
@@ -29,6 +29,17 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
if (Router::cancelSending(p->from, p->id))
txRelayCanceled++;
}
/* If the original transmitter is doing retransmissions (hopStart equals hopLimit) for a reliable transmission, e.g., when
the ACK got lost, we will handle the packet again to make sure it gets an ACK to its packet. */
bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit;
if (isRepeated) {
LOG_DEBUG("Repeated reliable tx");
if (!perhapsRebroadcast(p) && isToUs(p) && p->want_ack) {
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0);
}
}
return true;
}
@@ -41,14 +52,8 @@ bool FloodingRouter::isRebroadcaster()
config.device.rebroadcast_mode != meshtastic_Config_DeviceConfig_RebroadcastMode_NONE;
}
void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p)
{
bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0);
if (isAckorReply && !isToUs(p) && p->to != NODENUM_BROADCAST) {
// do not flood direct message that is ACKed or replied to
LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast.");
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM
}
if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) {
if (p->id != 0) {
if (isRebroadcaster()) {
@@ -63,17 +68,34 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
}
#endif
LOG_INFO("Rebroadcasting received floodmsg");
LOG_INFO("Rebroadcast received floodmsg");
// Note: we are careful to resend using the original senders node id
// We are careful not to call our hooked version of send() - because we don't want to check this again
Router::send(tosend);
return true;
} else {
LOG_DEBUG("Not rebroadcasting: Role = CLIENT_MUTE or Rebroadcast Mode = NONE");
LOG_DEBUG("No rebroadcast: Role = CLIENT_MUTE or Rebroadcast Mode = NONE");
}
} else {
LOG_DEBUG("Ignoring 0 id broadcast");
LOG_DEBUG("Ignore 0 id broadcast");
}
}
return false;
}
void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
{
bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0);
if (isAckorReply && !isToUs(p) && !isBroadcast(p->to)) {
// do not flood direct message that is ACKed or replied to
LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast");
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM
}
perhapsRebroadcast(p);
// handle the packet as normal
Router::sniffReceived(p, c);
}

View File

@@ -31,6 +31,10 @@ class FloodingRouter : public Router, protected PacketHistory
private:
bool isRebroadcaster();
/** Check if we should rebroadcast this packet, and do so if needed
* @return true if rebroadcasted */
bool perhapsRebroadcast(const meshtastic_MeshPacket *p);
public:
/**
* Constructor

View File

@@ -67,21 +67,23 @@ template <typename T> bool LR11x0Interface<T>::init()
power = LR1110_MAX_POWER;
if ((power > LR1120_MAX_POWER) &&
(config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) // clamp again if wide freq range
(config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) { // clamp again if wide freq range
power = LR1120_MAX_POWER;
preambleLength = 12; // 12 is the default for operation above 2GHz
}
limitPower();
#ifdef LR11X0_RF_SWITCH_SUBGHZ
pinMode(LR11X0_RF_SWITCH_SUBGHZ, OUTPUT);
digitalWrite(LR11X0_RF_SWITCH_SUBGHZ, getFreq() < 1e9 ? HIGH : LOW);
LOG_DEBUG("Setting RF0 switch to %s", getFreq() < 1e9 ? "SubGHz" : "2.4GHz");
LOG_DEBUG("Set RF0 switch to %s", getFreq() < 1e9 ? "SubGHz" : "2.4GHz");
#endif
#ifdef LR11X0_RF_SWITCH_2_4GHZ
pinMode(LR11X0_RF_SWITCH_2_4GHZ, OUTPUT);
digitalWrite(LR11X0_RF_SWITCH_2_4GHZ, getFreq() < 1e9 ? LOW : HIGH);
LOG_DEBUG("Setting RF1 switch to %s", getFreq() < 1e9 ? "SubGHz" : "2.4GHz");
LOG_DEBUG("Set RF1 switch to %s", getFreq() < 1e9 ? "SubGHz" : "2.4GHz");
#endif
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
@@ -120,7 +122,7 @@ template <typename T> bool LR11x0Interface<T>::init()
if (dioAsRfSwitch) {
lora.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table);
LOG_DEBUG("Setting DIO RF switch", res);
LOG_DEBUG("Set DIO RF switch", res);
}
if (res == RADIOLIB_ERR_NONE) {
@@ -159,11 +161,6 @@ template <typename T> bool LR11x0Interface<T>::reconfigure()
if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
// TODO: Confirm gain registers are okay now
// err = lora.setRxGain(true);
// assert(err == RADIOLIB_ERR_NONE);
err = lora.setSyncWord(syncWord);
assert(err == RADIOLIB_ERR_NONE);

View File

@@ -33,7 +33,7 @@ MeshModule::~MeshModule()
}
meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
uint8_t hopStart, uint8_t hopLimit)
uint8_t hopLimit)
{
meshtastic_Routing c = meshtastic_Routing_init_default;
@@ -50,7 +50,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
p->priority = meshtastic_MeshPacket_Priority_ACK;
p->hop_limit = routingModule->getHopLimitForResponse(hopStart, hopLimit); // Flood ACK back to original sender
p->hop_limit = hopLimit; // Flood ACK back to original sender
p->to = to;
p->decoded.request_id = idFrom;
p->channel = chIndex;
@@ -86,7 +86,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
auto ourNodeNum = nodeDB->getNodeNum();
bool toUs = mp.to == NODENUM_BROADCAST || isToUs(&mp);
bool toUs = isBroadcast(mp.to) || isToUs(&mp);
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;
@@ -151,7 +151,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
// If the requester didn't ask for a response we might need to discard unused replies to prevent memory leaks
if (pi.myReply) {
LOG_DEBUG("Discarding an unneeded response");
LOG_DEBUG("Discard an unneeded response");
packetPool.release(pi.myReply);
pi.myReply = NULL;
}
@@ -168,7 +168,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
if (isDecoded && mp.decoded.want_response && toUs) {
if (currentReply) {
printPacket("Sending response", currentReply);
printPacket("Send response", currentReply);
service->sendToMesh(currentReply);
currentReply = NULL;
} else if (mp.from != ourNodeNum && !ignoreRequest) {
@@ -181,8 +181,8 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
// bad.
routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel, mp.hop_start,
mp.hop_limit);
routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel,
routingModule->getHopLimitForResponse(mp.hop_start, mp.hop_limit));
}
}
@@ -295,4 +295,4 @@ bool MeshModule::isRequestingFocus()
} else
return false;
}
#endif
#endif

View File

@@ -40,7 +40,7 @@ struct UIFrameEvent {
enum Action {
REDRAW_ONLY, // Don't change which frames are show, just redraw, asap
REGENERATE_FRAMESET, // Regenerate (change? add? remove?) screen frames, honoring requestFocus()
REGENERATE_FRAMESET_BACKGROUND, // Regenerate screen frames, attempting to remain on the same frame throughout
REGENERATE_FRAMESET_BACKGROUND, // Regenerate screen frames, Attempt to remain on the same frame throughout
} action = REDRAW_ONLY;
// We might want to pass additional data inside this struct at some point
@@ -162,7 +162,7 @@ class MeshModule
virtual Observable<const UIFrameEvent *> *getUIFrameObservable() { return NULL; }
meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
uint8_t hopStart = 0, uint8_t hopLimit = 0);
uint8_t hopLimit = 0);
/// Send an error response for the specified packet.
meshtastic_MeshPacket *allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p);

View File

@@ -13,6 +13,7 @@
#include "TypeConversions.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "meshUtils.h"
#include "modules/NodeInfoModule.h"
#include "modules/PositionModule.h"
#include "power.h"
@@ -78,17 +79,19 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping
nodeDB->updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
bool isPreferredRebroadcaster =
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER, meshtastic_Config_DeviceConfig_Role_REPEATER);
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag &&
mp->decoded.portnum == meshtastic_PortNum_TELEMETRY_APP && mp->decoded.request_id > 0) {
LOG_DEBUG("Received telemetry response. Skip sending our NodeInfo."); // because this potentially a Repeater which will
// ignore our request for its NodeInfo
LOG_DEBUG("Received telemetry response. Skip sending our NodeInfo"); // because this potentially a Repeater which will
// ignore our request for its NodeInfo
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user &&
nodeInfoModule) {
LOG_INFO("Heard new node on channel %d, sending NodeInfo and asking for a response.", mp->channel);
nodeInfoModule && !isPreferredRebroadcaster && !nodeDB->isFull()) {
if (airTime->isTxAllowedChannelUtil(true)) {
LOG_INFO("Heard new node on ch. %d, send NodeInfo and ask for response", mp->channel);
nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel);
} else {
LOG_DEBUG("Skip sending NodeInfo due to > 25 percent channel util.");
LOG_DEBUG("Skip sending NodeInfo > 25%% ch. util");
}
}
@@ -164,7 +167,7 @@ NodeNum MeshService::getNodenumFromRequestId(uint32_t request_id)
void MeshService::handleToRadio(meshtastic_MeshPacket &p)
{
#if defined(ARCH_PORTDUINO) && !HAS_RADIO
// Simulates device is receiving a packet via the LoRa chip
// Simulates device received a packet via the LoRa chip
if (p.decoded.portnum == meshtastic_PortNum_SIMULATOR_APP) {
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
meshtastic_Compressed scratch;
@@ -180,7 +183,7 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
// Switch the port from PortNum_SIMULATOR_APP back to the original PortNum
p.decoded.portnum = decoded->portnum;
} else
LOG_ERROR("Error decoding protobuf for simulator message!");
LOG_ERROR("Error decoding proto for simulator message!");
}
// Let SimRadio receive as if it did via its LoRa chip
SimRadio::instance->startReceive(&p);
@@ -222,7 +225,7 @@ ErrorCode MeshService::sendQueueStatusToPhone(const meshtastic_QueueStatus &qs,
copied->mesh_packet_id = mesh_packet_id;
if (toPhoneQueueStatusQueue.numFree() == 0) {
LOG_INFO("tophone queue status queue is full, discarding oldest");
LOG_INFO("tophone queue status queue is full, discard oldest");
meshtastic_QueueStatus *d = toPhoneQueueStatusQueue.dequeuePtr(0);
if (d)
releaseQueueStatusToPool(d);
@@ -252,9 +255,14 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
LOG_DEBUG("Can't send status to phone");
}
if (res == ERRNO_OK && ccToPhone) { // Check if p is not released in case it couldn't be sent
if ((res == ERRNO_OK || res == ERRNO_SHOULD_RELEASE) && ccToPhone) { // Check if p is not released in case it couldn't be sent
sendToPhone(packetPool.allocCopy(*p));
}
// Router may ask us to release the packet if it wasn't sent
if (res == ERRNO_SHOULD_RELEASE) {
releaseToPool(p);
}
}
bool MeshService::trySendPosition(NodeNum dest, bool wantReplies)
@@ -266,14 +274,14 @@ bool MeshService::trySendPosition(NodeNum dest, bool wantReplies)
if (hasValidPosition(node)) {
#if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS
if (positionModule) {
LOG_INFO("Sending position ping to 0x%x, wantReplies=%d, channel=%d", dest, wantReplies, node->channel);
LOG_INFO("Send position ping to 0x%x, wantReplies=%d, channel=%d", dest, wantReplies, node->channel);
positionModule->sendOurPosition(dest, wantReplies, node->channel);
return true;
}
} else {
#endif
if (nodeInfoModule) {
LOG_INFO("Sending nodeinfo ping to 0x%x, wantReplies=%d, channel=%d", dest, wantReplies, node->channel);
LOG_INFO("Send nodeinfo ping to 0x%x, wantReplies=%d, channel=%d", dest, wantReplies, node->channel);
nodeInfoModule->sendOurNodeInfo(dest, wantReplies, node->channel);
}
}
@@ -298,12 +306,12 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p)
if (toPhoneQueue.numFree() == 0) {
if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) {
LOG_WARN("ToPhone queue is full, discarding oldest");
LOG_WARN("ToPhone queue is full, discard oldest");
meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
} else {
LOG_WARN("ToPhone queue is full, dropping packet.");
LOG_WARN("ToPhone queue is full, drop packet");
releaseToPool(p);
fromNum++; // Make sure to notify observers in case they are reconnected so they can get the packets
return;
@@ -316,9 +324,9 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p)
void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m)
{
LOG_DEBUG("Sending mqtt message on topic '%s' to client for proxy", m->topic);
LOG_DEBUG("Send mqtt message on topic '%s' to client for proxy", m->topic);
if (toPhoneMqttProxyQueue.numFree() == 0) {
LOG_WARN("MqttClientProxyMessagePool queue is full, discarding oldest");
LOG_WARN("MqttClientProxyMessagePool queue is full, discard oldest");
meshtastic_MqttClientProxyMessage *d = toPhoneMqttProxyQueue.dequeuePtr(0);
if (d)
releaseMqttClientProxyMessageToPool(d);
@@ -330,9 +338,9 @@ void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage
void MeshService::sendClientNotification(meshtastic_ClientNotification *n)
{
LOG_DEBUG("Sending client notification to phone");
LOG_DEBUG("Send client notification to phone");
if (toPhoneClientNotificationQueue.numFree() == 0) {
LOG_WARN("ClientNotification queue is full, discarding oldest");
LOG_WARN("ClientNotification queue is full, discard oldest");
meshtastic_ClientNotification *d = toPhoneClientNotificationQueue.dequeuePtr(0);
if (d)
releaseClientNotificationToPool(d);
@@ -380,13 +388,13 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
pos = gps->p;
} else {
// The GPS has lost lock
#ifdef GPS_EXTRAVERBOSE
#ifdef GPS_DEBUG
LOG_DEBUG("onGPSchanged() - lost validLocation");
#endif
}
// Used fixed position if configured regardless of GPS lock
if (config.position.fixed_position) {
LOG_WARN("Using fixed position");
LOG_WARN("Use fixed position");
pos = TypeConversions::ConvertToPosition(node->position);
}
@@ -418,4 +426,4 @@ uint32_t MeshService::GetTimeSinceMeshPacket(const meshtastic_MeshPacket *mp)
delta = 0;
return delta;
}
}

View File

@@ -16,6 +16,7 @@ typedef uint32_t PacketId; // A packet sequence number
#define ERRNO_NO_INTERFACES 33
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
#define ERRNO_DISABLED 34 // the interface is disabled
#define ERRNO_SHOULD_RELEASE 35 // no error, but the packet should still be released
#define ID_COUNTER_MASK (UINT32_MAX >> 22) // mask to select the counter portion of the ID
/*
@@ -57,4 +58,6 @@ bool isFromUs(const meshtastic_MeshPacket *p);
bool isToUs(const meshtastic_MeshPacket *p);
/* Some clients might not properly set priority, therefore we fix it here. */
void fixPriority(meshtastic_MeshPacket *p);
void fixPriority(meshtastic_MeshPacket *p);
bool isBroadcast(uint32_t dest);

View File

@@ -32,9 +32,14 @@
#if HAS_WIFI
#include "mesh/wifi/WiFiAPClient.h"
#endif
#include "SPILock.h"
#include "modules/StoreForwardModule.h"
#include <Preferences.h>
#include <esp_efuse.h>
#include <esp_efuse_table.h>
#include <nvs_flash.h>
#include <soc/efuse_reg.h>
#include <soc/soc.h>
#endif
#ifdef ARCH_PORTDUINO
@@ -56,6 +61,16 @@ meshtastic_LocalConfig config;
meshtastic_LocalModuleConfig moduleConfig;
meshtastic_ChannelFile channelFile;
#ifdef USERPREFS_USE_ADMIN_KEY_0
static unsigned char userprefs_admin_key_0[] = USERPREFS_USE_ADMIN_KEY_0;
#endif
#ifdef USERPREFS_USE_ADMIN_KEY_1
static unsigned char userprefs_admin_key_1[] = USERPREFS_USE_ADMIN_KEY_1;
#endif
#ifdef USERPREFS_USE_ADMIN_KEY_2
static unsigned char userprefs_admin_key_2[] = USERPREFS_USE_ADMIN_KEY_2;
#endif
bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
{
if (ostream) {
@@ -100,7 +115,7 @@ static uint8_t ourMacAddr[6];
NodeDB::NodeDB()
{
LOG_INFO("Initializing NodeDB");
LOG_INFO("Init NodeDB");
loadFromDisk();
cleanupMeshDB();
@@ -109,6 +124,44 @@ NodeDB::NodeDB()
uint32_t channelFileCRC = crc32Buffer(&channelFile, sizeof(channelFile));
int saveWhat = 0;
// bool hasUniqueId = false;
// Get device unique id
#if defined(ARCH_ESP32) && defined(ESP_EFUSE_OPTIONAL_UNIQUE_ID)
uint32_t unique_id[4];
// ESP32 factory burns a unique id in efuse for S2+ series and evidently C3+ series
// This is used for HMACs in the esp-rainmaker AIOT platform and seems to be a good choice for us
esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_OPTIONAL_UNIQUE_ID, unique_id, sizeof(unique_id) * 8);
if (err == ESP_OK) {
memcpy(myNodeInfo.device_id.bytes, unique_id, sizeof(unique_id));
myNodeInfo.device_id.size = 16;
hasUniqueId = true;
} else {
LOG_WARN("Failed to read unique id from efuse");
}
#elif defined(ARCH_NRF52)
// Nordic applies a FIPS compliant Random ID to each chip at the factory
// We concatenate the device address to the Random ID to create a unique ID for now
// This will likely utilize a crypto module in the future
uint64_t device_id_start = ((uint64_t)NRF_FICR->DEVICEID[1] << 32) | NRF_FICR->DEVICEID[0];
uint64_t device_id_end = ((uint64_t)NRF_FICR->DEVICEADDR[1] << 32) | NRF_FICR->DEVICEADDR[0];
memcpy(myNodeInfo.device_id.bytes, &device_id_start, sizeof(device_id_start));
memcpy(myNodeInfo.device_id.bytes + sizeof(device_id_start), &device_id_end, sizeof(device_id_end));
myNodeInfo.device_id.size = 16;
// Uncomment below to print the device id
// hasUniqueId = true;
#else
// FIXME - implement for other platforms
#endif
// if (hasUniqueId) {
// std::string deviceIdHex;
// for (size_t i = 0; i < myNodeInfo.device_id.size; ++i) {
// char buf[3];
// snprintf(buf, sizeof(buf), "%02X", myNodeInfo.device_id.bytes[i]);
// deviceIdHex += buf;
// }
// LOG_DEBUG("Device ID (HEX): %s", deviceIdHex.c_str());
// }
// likewise - we always want the app requirements to come from the running appload
myNodeInfo.min_app_version = 30200; // format is Mmmss (where M is 1+the numeric major number. i.e. 30200 means 2.2.00
@@ -132,21 +185,23 @@ NodeDB::NodeDB()
}
#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)) {
if (!owner.is_licensed) {
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("Generate new PKI keys");
crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes);
keygenSuccess = true;
}
} else {
LOG_INFO("Generating new PKI keys");
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);
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
@@ -171,6 +226,25 @@ NodeDB::NodeDB()
resetRadioConfig(); // If bogus settings got saved, then fix them
// nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d", config.lora.region, myNodeInfo.my_node_num, numMeshNodes);
// If we are setup to broadcast on the default channel, ensure that the telemetry intervals are coerced to the minimum value
// of 30 minutes or more
if (channels.isDefaultChannel(channels.getPrimaryIndex())) {
LOG_DEBUG("Coerce telemetry to min of 30 minutes on defaults");
moduleConfig.telemetry.device_update_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.device_update_interval, min_default_telemetry_interval_secs);
moduleConfig.telemetry.environment_update_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.environment_update_interval, min_default_telemetry_interval_secs);
moduleConfig.telemetry.air_quality_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.air_quality_interval, min_default_telemetry_interval_secs);
moduleConfig.telemetry.power_update_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.power_update_interval, min_default_telemetry_interval_secs);
moduleConfig.telemetry.health_update_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.health_update_interval, min_default_telemetry_interval_secs);
}
// Ensure that the neighbor info update interval is coerced to the minimum
moduleConfig.neighbor_info.update_interval =
Default::getConfiguredOrMinimumValue(moduleConfig.neighbor_info.update_interval, min_neighbor_info_broadcast_secs);
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
saveWhat |= SEGMENT_DEVICESTATE;
if (configCRC != crc32Buffer(&config, sizeof(config)))
@@ -182,6 +256,31 @@ NodeDB::NodeDB()
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
config.position.gps_enabled = 0;
}
#ifdef USERPREFS_FIXED_GPS
if (myNodeInfo.reboot_count == 1) { // Check if First boot ever or after Factory Reset.
meshtastic_Position fixedGPS = meshtastic_Position_init_default;
#ifdef USERPREFS_FIXED_GPS_LAT
fixedGPS.latitude_i = (int32_t)(USERPREFS_FIXED_GPS_LAT * 1e7);
fixedGPS.has_latitude_i = true;
#endif
#ifdef USERPREFS_FIXED_GPS_LON
fixedGPS.longitude_i = (int32_t)(USERPREFS_FIXED_GPS_LON * 1e7);
fixedGPS.has_longitude_i = true;
#endif
#ifdef USERPREFS_FIXED_GPS_ALT
fixedGPS.altitude = USERPREFS_FIXED_GPS_ALT;
fixedGPS.has_altitude = true;
#endif
#if defined(USERPREFS_FIXED_GPS_LAT) && defined(USERPREFS_FIXED_GPS_LON)
fixedGPS.location_source = meshtastic_Position_LocSource_LOC_MANUAL;
config.has_position = true;
info->has_position = true;
info->position = TypeConversions::ConvertToPositionLite(fixedGPS);
nodeDB->setLocalPosition(fixedGPS);
config.position.fixed_position = true;
#endif
}
#endif
saveToDisk(saveWhat);
}
@@ -206,6 +305,11 @@ bool isToUs(const meshtastic_MeshPacket *p)
return p->to == nodeDB->getNodeNum();
}
bool isBroadcast(uint32_t dest)
{
return dest == NODENUM_BROADCAST || dest == NODENUM_BROADCAST_NO_LORA;
}
bool NodeDB::resetRadioConfig(bool factory_reset)
{
bool didFactoryReset = false;
@@ -217,7 +321,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
}
if (channelFile.channels_count != MAX_NUM_CHANNELS) {
LOG_INFO("Setting default channel and radio preferences!");
LOG_INFO("Set default channel and radio preferences!");
channels.initDefaults();
}
@@ -228,7 +332,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
initRegion();
if (didFactoryReset) {
LOG_INFO("Rebooting due to factory reset");
LOG_INFO("Reboot due to factory reset");
screen->startAlert("Rebooting...");
rebootAtMsec = millis() + (5 * 1000);
}
@@ -238,7 +342,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
bool NodeDB::factoryReset(bool eraseBleBonds)
{
LOG_INFO("Performing factory reset!");
LOG_INFO("Perform factory reset!");
// first, remove the "/prefs" (this removes most prefs)
rmDir("/prefs");
#ifdef FSCom
@@ -254,14 +358,14 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
// third, write everything to disk
saveToDisk();
if (eraseBleBonds) {
LOG_INFO("Erasing BLE bonds");
LOG_INFO("Erase BLE bonds");
#ifdef ARCH_ESP32
// This will erase what's in NVS including ssl keys, persistent variables and ble pairing
nvs_flash_erase();
#endif
#ifdef ARCH_NRF52
Bluefruit.begin();
LOG_INFO("Clearing bluetooth bonds!");
LOG_INFO("Clear bluetooth bonds!");
bond_print_list(BLE_GAP_ROLE_PERIPH);
bond_print_list(BLE_GAP_ROLE_CENTRAL);
Bluefruit.Periph.clearBonds();
@@ -278,7 +382,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
if (shouldPreserveKey) {
memcpy(private_key_temp, config.security.private_key.bytes, config.security.private_key.size);
}
LOG_INFO("Installing default LocalConfig");
LOG_INFO("Install default LocalConfig");
memset(&config, 0, sizeof(meshtastic_LocalConfig));
config.version = DEVICESTATE_CUR_VER;
config.has_device = true;
@@ -312,11 +416,37 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
#else
config.lora.ignore_mqtt = false;
#endif
#ifdef USERPREFS_USE_ADMIN_KEY
memcpy(config.security.admin_key[0].bytes, USERPREFS_ADMIN_KEY, 32);
config.security.admin_key[0].size = 32;
config.security.admin_key_count = 1;
// Initialize admin_key_count to zero
byte numAdminKeys = 0;
#ifdef USERPREFS_USE_ADMIN_KEY_0
// Check if USERPREFS_ADMIN_KEY_0 is non-empty
if (sizeof(userprefs_admin_key_0) > 0) {
memcpy(config.security.admin_key[0].bytes, userprefs_admin_key_0, 32);
config.security.admin_key[0].size = 32;
numAdminKeys++;
}
#endif
#ifdef USERPREFS_USE_ADMIN_KEY_1
// Check if USERPREFS_ADMIN_KEY_1 is non-empty
if (sizeof(userprefs_admin_key_1) > 0) {
memcpy(config.security.admin_key[1].bytes, userprefs_admin_key_1, 32);
config.security.admin_key[1].size = 32;
numAdminKeys++;
}
#endif
#ifdef USERPREFS_USE_ADMIN_KEY_2
// Check if USERPREFS_ADMIN_KEY_2 is non-empty
if (sizeof(userprefs_admin_key_2) > 0) {
memcpy(config.security.admin_key[2].bytes, userprefs_admin_key_2, 32);
config.security.admin_key[2].size = 32;
numAdminKeys++;
}
#endif
config.security.admin_key_count = numAdminKeys;
if (shouldPreserveKey) {
config.security.private_key.size = 32;
memcpy(config.security.private_key.bytes, private_key_temp, config.security.private_key.size);
@@ -369,8 +499,13 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
#else
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
#endif
#ifdef USERPREFS_FIXED_BLUETOOTH
config.bluetooth.fixed_pin = USERPREFS_FIXED_BLUETOOTH;
config.bluetooth.mode = meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
#else
config.bluetooth.mode = hasScreen ? meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN
: meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
#endif
// for backward compat, default position flags are ALT+MSL
config.position.position_flags =
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL |
@@ -383,7 +518,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
#ifdef RAK4630
config.display.wake_on_tap_or_motion = true;
#endif
#ifdef T_WATCH_S3
#if defined(T_WATCH_S3) || defined(SENSECAP_INDICATOR)
config.display.screen_on_secs = 30;
config.display.wake_on_tap_or_motion = true;
#endif
@@ -407,7 +542,7 @@ void NodeDB::initConfigIntervals()
config.display.screen_on_secs = default_screen_on_secs;
#if defined(T_WATCH_S3) || defined(T_DECK)
#if defined(T_WATCH_S3) || defined(T_DECK) || defined(RAK14014) || defined(SENSECAP_INDICATOR)
config.power.is_power_saving = true;
config.display.screen_on_secs = 30;
config.power.wait_bluetooth_secs = 30;
@@ -416,7 +551,7 @@ void NodeDB::initConfigIntervals()
void NodeDB::installDefaultModuleConfig()
{
LOG_INFO("Installing default ModuleConfig");
LOG_INFO("Install default ModuleConfig");
memset(&moduleConfig, 0, sizeof(meshtastic_ModuleConfig));
moduleConfig.version = DEVICESTATE_CUR_VER;
@@ -494,8 +629,10 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
if (role == meshtastic_Config_DeviceConfig_Role_ROUTER) {
initConfigIntervals();
initModuleConfigIntervals();
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY;
} else if (role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
config.display.screen_on_secs = 1;
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY;
} else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) {
moduleConfig.telemetry.environment_measurement_enabled = true;
moduleConfig.telemetry.environment_update_interval = 300;
@@ -549,7 +686,7 @@ void NodeDB::initModuleConfigIntervals()
void NodeDB::installDefaultChannels()
{
LOG_INFO("Installing default ChannelFile");
LOG_INFO("Install default ChannelFile");
memset(&channelFile, 0, sizeof(meshtastic_ChannelFile));
channelFile.version = DEVICESTATE_CUR_VER;
}
@@ -579,7 +716,7 @@ void NodeDB::removeNodeByNum(NodeNum nodeNum)
numMeshNodes -= removed;
std::fill(devicestate.node_db_lite.begin() + numMeshNodes, devicestate.node_db_lite.begin() + numMeshNodes + 1,
meshtastic_NodeInfoLite());
LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Saving changes...", removed);
LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Save changes", removed);
saveDeviceStateToDisk();
}
@@ -616,7 +753,7 @@ void NodeDB::cleanupMeshDB()
void NodeDB::installDefaultDeviceState()
{
LOG_INFO("Installing default DeviceState");
LOG_INFO("Install default DeviceState");
// memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
numMeshNodes = 0;
@@ -674,7 +811,7 @@ void NodeDB::pickNewNodeNum()
nodeNum, found->user.macaddr[4], found->user.macaddr[5], ourMacAddr[4], ourMacAddr[5], candidate);
nodeNum = candidate;
}
LOG_DEBUG("Using nodenum 0x%x ", nodeNum);
LOG_DEBUG("Use nodenum 0x%x ", nodeNum);
myNodeInfo.my_node_num = nodeNum;
}
@@ -694,7 +831,7 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t
auto f = FSCom.open(filename, FILE_O_READ);
if (f) {
LOG_INFO("Loading %s", filename);
LOG_INFO("Load %s", filename);
pb_istream_t stream = {&readcb, &f, protoSize};
memset(dest_struct, 0, objSize);
@@ -722,8 +859,13 @@ void NodeDB::loadFromDisk()
0; // Mark the current device state as completely unusable, so that if we fail reading the entire file from
// disk we will still factoryReset to restore things.
#ifdef ARCH_ESP32
if (FSCom.exists("/static/static"))
rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release
#endif
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES * sizeof(meshtastic_NodeInfo),
auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES_FS * sizeof(meshtastic_NodeInfo),
sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg, &devicestate);
// See https://github.com/meshtastic/firmware/issues/4184#issuecomment-2269390786
@@ -735,13 +877,17 @@ void NodeDB::loadFromDisk()
// installDefaultDeviceState(); // Our in RAM copy might now be corrupt
//} else {
if (devicestate.version < DEVICESTATE_MIN_VER) {
LOG_WARN("Devicestate %d is old, discarding", devicestate.version);
LOG_WARN("Devicestate %d is old, discard", devicestate.version);
installDefaultDeviceState();
} else {
LOG_INFO("Loaded saved devicestate version %d, with nodecount: %d", devicestate.version, devicestate.node_db_lite.size());
meshNodes = &devicestate.node_db_lite;
numMeshNodes = devicestate.node_db_lite.size();
}
if (numMeshNodes > MAX_NUM_NODES) {
LOG_WARN("Node count %d exceeds MAX_NUM_NODES %d, truncating", numMeshNodes, MAX_NUM_NODES);
numMeshNodes = MAX_NUM_NODES;
}
meshNodes->resize(MAX_NUM_NODES);
state = loadProto(configFileName, meshtastic_LocalConfig_size, sizeof(meshtastic_LocalConfig), &meshtastic_LocalConfig_msg,
@@ -750,20 +896,68 @@ void NodeDB::loadFromDisk()
installDefaultConfig(); // Our in RAM copy might now be corrupt
} else {
if (config.version < DEVICESTATE_MIN_VER) {
LOG_WARN("config %d is old, discarding", config.version);
LOG_WARN("config %d is old, discard", config.version);
installDefaultConfig(true);
} else {
LOG_INFO("Loaded saved config version %d", config.version);
}
}
// Make sure we load hard coded admin keys even when the configuration file has none.
// Initialize admin_key_count to zero
byte numAdminKeys = 0;
uint16_t sum = 0;
#ifdef USERPREFS_USE_ADMIN_KEY_0
for (uint8_t b = 0; b < 32; b++) {
sum += config.security.admin_key[0].bytes[b];
}
if (sum == 0) {
numAdminKeys += 1;
LOG_INFO("Admin 0 key zero. Loading hard coded key from user preferences.");
memcpy(config.security.admin_key[0].bytes, userprefs_admin_key_0, 32);
config.security.admin_key[0].size = 32;
config.security.admin_key_count = numAdminKeys;
saveToDisk(SEGMENT_CONFIG);
}
#endif
#ifdef USERPREFS_USE_ADMIN_KEY_1
sum = 0;
for (uint8_t b = 0; b < 32; b++) {
sum += config.security.admin_key[1].bytes[b];
}
if (sum == 0) {
numAdminKeys += 1;
LOG_INFO("Admin 1 key zero. Loading hard coded key from user preferences.");
memcpy(config.security.admin_key[1].bytes, userprefs_admin_key_1, 32);
config.security.admin_key[1].size = 32;
config.security.admin_key_count = numAdminKeys;
saveToDisk(SEGMENT_CONFIG);
}
#endif
#ifdef USERPREFS_USE_ADMIN_KEY_2
sum = 0;
for (uint8_t b = 0; b < 32; b++) {
sum += config.security.admin_key[2].bytes[b];
}
if (sum == 0) {
numAdminKeys += 1;
LOG_INFO("Admin 2 key zero. Loading hard coded key from user preferences.");
memcpy(config.security.admin_key[2].bytes, userprefs_admin_key_2, 32);
config.security.admin_key[2].size = 32;
config.security.admin_key_count = numAdminKeys;
saveToDisk(SEGMENT_CONFIG);
}
#endif
state = loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig),
&meshtastic_LocalModuleConfig_msg, &moduleConfig);
if (state != LoadFileResult::LOAD_SUCCESS) {
installDefaultModuleConfig(); // Our in RAM copy might now be corrupt
} else {
if (moduleConfig.version < DEVICESTATE_MIN_VER) {
LOG_WARN("moduleConfig %d is old, discarding", moduleConfig.version);
LOG_WARN("moduleConfig %d is old, discard", moduleConfig.version);
installDefaultModuleConfig();
} else {
LOG_INFO("Loaded saved moduleConfig version %d", moduleConfig.version);
@@ -776,7 +970,7 @@ void NodeDB::loadFromDisk()
installDefaultChannels(); // Our in RAM copy might now be corrupt
} else {
if (channelFile.version < DEVICESTATE_MIN_VER) {
LOG_WARN("channelFile %d is old, discarding", channelFile.version);
LOG_WARN("channelFile %d is old, discard", channelFile.version);
installDefaultChannels();
} else {
LOG_INFO("Loaded saved channelFile version %d", channelFile.version);
@@ -808,11 +1002,14 @@ void NodeDB::loadFromDisk()
bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct,
bool fullAtomic)
{
#ifdef ARCH_ESP32
concurrency::LockGuard g(spiLock);
#endif
bool okay = false;
#ifdef FSCom
auto f = SafeFile(filename, fullAtomic);
LOG_INFO("Saving %s", filename);
LOG_INFO("Save %s", filename);
pb_ostream_t stream = {&writecb, static_cast<Print *>(&f), protoSize};
if (!pb_encode(&stream, fields, dest_struct)) {
@@ -905,7 +1102,7 @@ bool NodeDB::saveToDisk(int saveWhat)
bool success = saveToDiskNoRetry(saveWhat);
if (!success) {
LOG_ERROR("Failed to save to disk, retrying...");
LOG_ERROR("Failed to save to disk, retrying");
#ifdef ARCH_NRF52 // @geeksville is not ready yet to say we should do this on other platforms. See bug #4184 discussion
FSCom.format();
@@ -1055,7 +1252,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
// we copy the key into the incoming packet, to prevent overwrite
memcpy(p.public_key.bytes, info->user.public_key.bytes, 32);
} else {
LOG_INFO("Updating Node Pubkey!");
LOG_INFO("Update Node Pubkey!");
}
}
#endif
@@ -1070,7 +1267,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
}
if (nodeId != getNodeNum())
info->channel = channelIndex; // Set channel we need to use to reach this node (but don't set our own channel)
LOG_DEBUG("updating changed=%d user %s/%s, channel=%d", changed, info->user.long_name, info->user.short_name, info->channel);
LOG_DEBUG("Update changed=%d user %s/%s, channel=%d", changed, info->user.long_name, info->user.short_name, info->channel);
info->has_user = true;
if (changed) {
@@ -1081,7 +1278,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
// We just changed something about the user, store our DB
Throttle::execute(
&lastNodeDbSave, ONE_MINUTE_MS, []() { nodeDB->saveToDisk(SEGMENT_DEVICESTATE); },
[]() { LOG_DEBUG("Deferring NodeDB saveToDisk for now"); }); // since we saved less than a minute ago
[]() { LOG_DEBUG("Defer NodeDB saveToDisk for now"); }); // since we saved less than a minute ago
}
return changed;
@@ -1135,16 +1332,20 @@ meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n)
return NULL;
}
// returns true if the maximum number of nodes is reached or we are running low on memory
bool NodeDB::isFull()
{
return (numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < MINIMUM_SAFE_FREE_HEAP);
}
/// Find a node in our DB, create an empty NodeInfo if missing
meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
{
meshtastic_NodeInfoLite *lite = getMeshNode(n);
if (!lite) {
if ((numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < MINIMUM_SAFE_FREE_HEAP)) {
if (screen)
screen->print("Warn: node database full!\nErasing oldest entry\n");
LOG_WARN("Node database full with %i nodes and %i bytes free! Erasing oldest entry", numMeshNodes,
if (isFull()) {
LOG_INFO("Node database full with %i nodes and %i bytes free. Erasing oldest entry", numMeshNodes,
memGet.getFreeHeap());
// look for oldest node and erase it
uint32_t oldest = UINT32_MAX;
@@ -1153,12 +1354,12 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
int oldestBoringIndex = -1;
for (int i = 1; i < numMeshNodes; i++) {
// Simply the oldest non-favorite node
if (!meshNodes->at(i).is_favorite && meshNodes->at(i).last_heard < oldest) {
if (!meshNodes->at(i).is_favorite && !meshNodes->at(i).is_ignored && meshNodes->at(i).last_heard < oldest) {
oldest = meshNodes->at(i).last_heard;
oldestIndex = i;
}
// The oldest "boring" node
if (!meshNodes->at(i).is_favorite && meshNodes->at(i).user.public_key.size == 0 &&
if (!meshNodes->at(i).is_favorite && !meshNodes->at(i).is_ignored && meshNodes->at(i).user.public_key.size == 0 &&
meshNodes->at(i).last_heard < oldestBoring) {
oldestBoring = meshNodes->at(i).last_heard;
oldestBoringIndex = i;
@@ -1194,9 +1395,9 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co
if (screen)
screen->print(lcd.c_str());
if (filename) {
LOG_ERROR("NOTE! Recording critical error %d at %s:%lu", code, filename, address);
LOG_ERROR("NOTE! Record critical error %d at %s:%lu", code, filename, address);
} else {
LOG_ERROR("NOTE! Recording critical error %d, address=0x%lx", code, address);
LOG_ERROR("NOTE! Record critical error %d, address=0x%lx", code, address);
}
// Record error to DB
@@ -1205,7 +1406,7 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co
// Currently portuino is mostly used for simulation. Make sure the user notices something really bad happened
#ifdef ARCH_PORTDUINO
LOG_ERROR("A critical failure occurred, portduino is exiting...");
LOG_ERROR("A critical failure occurred, portduino is exiting");
exit(2);
#endif
}
}

View File

@@ -147,17 +147,20 @@ class NodeDB
meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
size_t getNumMeshNodes() { return numMeshNodes; }
// returns true if the maximum number of nodes is reached or we are running low on memory
bool isFull();
void clearLocalPosition();
void setLocalPosition(meshtastic_Position position, bool timeOnly = false)
{
if (timeOnly) {
LOG_DEBUG("Setting local position time only: time=%u timestamp=%u", position.time, position.timestamp);
LOG_DEBUG("Set local position time only: time=%u timestamp=%u", position.time, position.timestamp);
localPosition.time = position.time;
localPosition.timestamp = position.timestamp > 0 ? position.timestamp : position.time;
return;
}
LOG_DEBUG("Setting local position: lat=%i lon=%i time=%u timestamp=%u", position.latitude_i, position.longitude_i,
LOG_DEBUG("Set local position: lat=%i lon=%i time=%u timestamp=%u", position.latitude_i, position.longitude_i,
position.time, position.timestamp);
localPosition = position;
}

View File

@@ -19,7 +19,7 @@ PacketHistory::PacketHistory()
bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate)
{
if (p->id == 0) {
LOG_DEBUG("Ignoring message with zero id");
LOG_DEBUG("Ignore message with zero id");
return false; // Not a floodable message ID, so we don't care
}

View File

@@ -57,14 +57,14 @@ void PhoneAPI::handleStartConfig()
filesManifest = getFiles("/", 10);
LOG_DEBUG("Got %d files in manifest", filesManifest.size());
LOG_INFO("Starting API client config");
LOG_INFO("Start API client config");
nodeInfoForPhone.num = 0; // Don't keep returning old nodeinfos
resetReadIndex();
}
void PhoneAPI::close()
{
LOG_INFO("PhoneAPI::close()");
LOG_DEBUG("PhoneAPI::close()");
if (state != STATE_SEND_NOTHING) {
state = STATE_SEND_NOTHING;
@@ -122,7 +122,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
handleStartConfig();
break;
case meshtastic_ToRadio_disconnect_tag:
LOG_INFO("Disconnecting from phone");
LOG_INFO("Disconnect from phone");
close();
break;
case meshtastic_ToRadio_xmodemPacket_tag:
@@ -133,7 +133,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
break;
#if !MESHTASTIC_EXCLUDE_MQTT
case meshtastic_ToRadio_mqttClientProxyMessage_tag:
LOG_INFO("Got MqttClientProxy message");
LOG_DEBUG("Got MqttClientProxy message");
if (mqtt && moduleConfig.mqtt.proxy_to_client_enabled && moduleConfig.mqtt.enabled &&
(channels.anyMqttEnabled() || moduleConfig.mqtt.map_reporting_enabled)) {
mqtt->onClientProxyReceive(toRadioScratch.mqttClientProxyMessage);
@@ -148,11 +148,10 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
break;
default:
// Ignore nop messages
// LOG_DEBUG("Error: unexpected ToRadio variant");
break;
}
} else {
LOG_ERROR("Error: ignoring malformed toradio");
LOG_ERROR("Error: ignore malformed toradio");
}
return false;
@@ -179,7 +178,6 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
size_t PhoneAPI::getFromRadio(uint8_t *buf)
{
if (!available()) {
// LOG_DEBUG("getFromRadio=not available");
return 0;
}
// In case we send a FromRadio packet
@@ -188,14 +186,15 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// Advance states as needed
switch (state) {
case STATE_SEND_NOTHING:
LOG_INFO("getFromRadio=STATE_SEND_NOTHING");
LOG_DEBUG("FromRadio=STATE_SEND_NOTHING");
break;
case STATE_SEND_MY_INFO:
LOG_INFO("getFromRadio=STATE_SEND_MY_INFO");
LOG_DEBUG("FromRadio=STATE_SEND_MY_INFO");
// If the user has specified they don't want our node to share its location, make sure to tell the phone
// app not to send locations on our behalf.
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag;
strncpy(myNodeInfo.pio_env, optstr(APP_ENV), sizeof(myNodeInfo.pio_env));
fromRadioScratch.my_info = myNodeInfo;
state = STATE_SEND_OWN_NODEINFO;
@@ -203,7 +202,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
break;
case STATE_SEND_OWN_NODEINFO: {
LOG_INFO("getFromRadio=STATE_SEND_OWN_NODEINFO");
LOG_DEBUG("Send My NodeInfo");
auto us = nodeDB->readNextMeshNode(readIndex);
if (us) {
nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(us);
@@ -219,62 +218,70 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
}
case STATE_SEND_METADATA:
LOG_INFO("getFromRadio=STATE_SEND_METADATA");
LOG_DEBUG("Send device metadata");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag;
fromRadioScratch.metadata = getDeviceMetadata();
state = STATE_SEND_CHANNELS;
break;
case STATE_SEND_CHANNELS:
LOG_INFO("getFromRadio=STATE_SEND_CHANNELS");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_channel_tag;
fromRadioScratch.channel = channels.getByIndex(config_state);
config_state++;
// Advance when we have sent all of our Channels
if (config_state >= MAX_NUM_CHANNELS) {
LOG_DEBUG("Send channels %d", config_state);
state = STATE_SEND_CONFIG;
config_state = _meshtastic_AdminMessage_ConfigType_MIN + 1;
}
break;
case STATE_SEND_CONFIG:
LOG_INFO("getFromRadio=STATE_SEND_CONFIG");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_tag;
switch (config_state) {
case meshtastic_Config_device_tag:
LOG_DEBUG("Send config: device");
fromRadioScratch.config.which_payload_variant = meshtastic_Config_device_tag;
fromRadioScratch.config.payload_variant.device = config.device;
break;
case meshtastic_Config_position_tag:
LOG_DEBUG("Send config: position");
fromRadioScratch.config.which_payload_variant = meshtastic_Config_position_tag;
fromRadioScratch.config.payload_variant.position = config.position;
break;
case meshtastic_Config_power_tag:
LOG_DEBUG("Send config: power");
fromRadioScratch.config.which_payload_variant = meshtastic_Config_power_tag;
fromRadioScratch.config.payload_variant.power = config.power;
fromRadioScratch.config.payload_variant.power.ls_secs = default_ls_secs;
break;
case meshtastic_Config_network_tag:
LOG_DEBUG("Send config: network");
fromRadioScratch.config.which_payload_variant = meshtastic_Config_network_tag;
fromRadioScratch.config.payload_variant.network = config.network;
break;
case meshtastic_Config_display_tag:
LOG_DEBUG("Send config: display");
fromRadioScratch.config.which_payload_variant = meshtastic_Config_display_tag;
fromRadioScratch.config.payload_variant.display = config.display;
break;
case meshtastic_Config_lora_tag:
LOG_DEBUG("Send config: lora");
fromRadioScratch.config.which_payload_variant = meshtastic_Config_lora_tag;
fromRadioScratch.config.payload_variant.lora = config.lora;
break;
case meshtastic_Config_bluetooth_tag:
LOG_DEBUG("Send config: bluetooth");
fromRadioScratch.config.which_payload_variant = meshtastic_Config_bluetooth_tag;
fromRadioScratch.config.payload_variant.bluetooth = config.bluetooth;
break;
case meshtastic_Config_security_tag:
LOG_DEBUG("Send config: security");
fromRadioScratch.config.which_payload_variant = meshtastic_Config_security_tag;
fromRadioScratch.config.payload_variant.security = config.security;
break;
case meshtastic_Config_sessionkey_tag:
LOG_DEBUG("Send config: sessionkey");
fromRadioScratch.config.which_payload_variant = meshtastic_Config_sessionkey_tag;
break;
default:
@@ -293,58 +300,70 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
break;
case STATE_SEND_MODULECONFIG:
LOG_INFO("getFromRadio=STATE_SEND_MODULECONFIG");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_moduleConfig_tag;
switch (config_state) {
case meshtastic_ModuleConfig_mqtt_tag:
LOG_DEBUG("Send module config: mqtt");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_mqtt_tag;
fromRadioScratch.moduleConfig.payload_variant.mqtt = moduleConfig.mqtt;
break;
case meshtastic_ModuleConfig_serial_tag:
LOG_DEBUG("Send module config: serial");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_serial_tag;
fromRadioScratch.moduleConfig.payload_variant.serial = moduleConfig.serial;
break;
case meshtastic_ModuleConfig_external_notification_tag:
LOG_DEBUG("Send module config: ext notification");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_external_notification_tag;
fromRadioScratch.moduleConfig.payload_variant.external_notification = moduleConfig.external_notification;
break;
case meshtastic_ModuleConfig_store_forward_tag:
LOG_DEBUG("Send module config: store forward");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_store_forward_tag;
fromRadioScratch.moduleConfig.payload_variant.store_forward = moduleConfig.store_forward;
break;
case meshtastic_ModuleConfig_range_test_tag:
LOG_DEBUG("Send module config: range test");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_range_test_tag;
fromRadioScratch.moduleConfig.payload_variant.range_test = moduleConfig.range_test;
break;
case meshtastic_ModuleConfig_telemetry_tag:
LOG_DEBUG("Send module config: telemetry");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_telemetry_tag;
fromRadioScratch.moduleConfig.payload_variant.telemetry = moduleConfig.telemetry;
break;
case meshtastic_ModuleConfig_canned_message_tag:
LOG_DEBUG("Send module config: canned message");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_canned_message_tag;
fromRadioScratch.moduleConfig.payload_variant.canned_message = moduleConfig.canned_message;
break;
case meshtastic_ModuleConfig_audio_tag:
LOG_DEBUG("Send module config: audio");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_audio_tag;
fromRadioScratch.moduleConfig.payload_variant.audio = moduleConfig.audio;
break;
case meshtastic_ModuleConfig_remote_hardware_tag:
LOG_DEBUG("Send module config: remote hardware");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag;
fromRadioScratch.moduleConfig.payload_variant.remote_hardware = moduleConfig.remote_hardware;
break;
case meshtastic_ModuleConfig_neighbor_info_tag:
LOG_DEBUG("Send module config: neighbor info");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag;
fromRadioScratch.moduleConfig.payload_variant.neighbor_info = moduleConfig.neighbor_info;
break;
case meshtastic_ModuleConfig_detection_sensor_tag:
LOG_DEBUG("Send module config: detection sensor");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
fromRadioScratch.moduleConfig.payload_variant.detection_sensor = moduleConfig.detection_sensor;
break;
case meshtastic_ModuleConfig_ambient_lighting_tag:
LOG_DEBUG("Send module config: ambient lighting");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag;
fromRadioScratch.moduleConfig.payload_variant.ambient_lighting = moduleConfig.ambient_lighting;
break;
case meshtastic_ModuleConfig_paxcounter_tag:
LOG_DEBUG("Send module config: paxcounter");
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag;
fromRadioScratch.moduleConfig.payload_variant.paxcounter = moduleConfig.paxcounter;
break;
@@ -362,7 +381,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
break;
case STATE_SEND_OTHER_NODEINFOS: {
LOG_INFO("getFromRadio=STATE_SEND_OTHER_NODEINFOS");
LOG_DEBUG("Send known nodes");
if (nodeInfoForPhone.num != 0) {
LOG_INFO("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s", nodeInfoForPhone.num, nodeInfoForPhone.last_heard,
nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name);
@@ -371,7 +390,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// Stay in current state until done sending nodeinfos
nodeInfoForPhone.num = 0; // We just consumed a nodeinfo, will need a new one next time
} else {
LOG_INFO("Done sending nodeinfos");
LOG_DEBUG("Done sending nodeinfo");
state = STATE_SEND_FILEMANIFEST;
// Go ahead and send that ID right now
return getFromRadio(buf);
@@ -380,7 +399,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
}
case STATE_SEND_FILEMANIFEST: {
LOG_INFO("getFromRadio=STATE_SEND_FILEMANIFEST");
LOG_DEBUG("FromRadio=STATE_SEND_FILEMANIFEST");
// last element
if (config_state == filesManifest.size()) { // also handles an empty filesManifest
config_state = 0;
@@ -403,7 +422,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
case STATE_SEND_PACKETS:
pauseBluetoothLogging = false;
// Do we have a message from the mesh or packet from the local device?
LOG_INFO("getFromRadio=STATE_SEND_PACKETS");
LOG_DEBUG("FromRadio=STATE_SEND_PACKETS");
if (queueStatusPacketForPhone) {
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_queueStatus_tag;
fromRadioScratch.queueStatus = *queueStatusPacketForPhone;
@@ -441,17 +460,16 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// VERY IMPORTANT to not print debug messages while writing to fromRadioScratch - because we use that same buffer
// for logging (when we are encapsulating with protobufs)
// LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes", fromRadioScratch.which_payload_variant, numbytes);
return numbytes;
}
LOG_DEBUG("no FromRadio packet available");
LOG_DEBUG("No FromRadio packet available");
return 0;
}
void PhoneAPI::sendConfigComplete()
{
LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID");
LOG_INFO("Config Send Complete");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag;
fromRadioScratch.config_complete_id = config_nonce;
config_nonce = 0;
@@ -551,7 +569,6 @@ bool PhoneAPI::available()
if (!packetForPhone)
packetForPhone = service->getForPhone();
hasPacket = !!packetForPhone;
// LOG_DEBUG("available hasPacket=%d", hasPacket);
return hasPacket;
}
default:
@@ -596,21 +613,24 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
{
printPacket("PACKET FROM PHONE", &p);
// For use with the simulator, we should not ignore duplicate packets
#if !(defined(ARCH_PORTDUINO) && !HAS_RADIO)
if (p.id > 0 && wasSeenRecently(p.id)) {
LOG_DEBUG("Ignoring packet from phone, already seen recently");
LOG_DEBUG("Ignore packet from phone, already seen recently");
return false;
}
#endif
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", p.decoded.portnum);
LOG_WARN("Rate limit portnum %d", 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", p.decoded.portnum);
LOG_WARN("Rate limit portnum %d", p.decoded.portnum);
meshtastic_QueueStatus qs = router->getQueueStatus();
service->sendQueueStatusToPhone(qs, 0, p.id);
// FIXME: Figure out why this continues to happen
@@ -629,11 +649,11 @@ int PhoneAPI::onNotify(uint32_t newValue)
// doesn't call this from idle)
if (state == STATE_SEND_PACKETS) {
LOG_INFO("Telling client we have new packets %u", newValue);
LOG_INFO("Tell client we have new packets %u", newValue);
onNowHasData(newValue);
} else {
LOG_DEBUG("(Client not yet interested in packets)");
}
return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one
}
}

View File

@@ -91,7 +91,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) {
decoded = &scratch;
} else {
LOG_ERROR("Error decoding protobuf module!");
LOG_ERROR("Error decoding proto module!");
// if we can't decode it, nobody can process it!
return ProcessMessage::STOP;
}
@@ -112,7 +112,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) {
decoded = &scratch;
} else {
LOG_ERROR("Error decoding protobuf module!");
LOG_ERROR("Error decoding proto module!");
// if we can't decode it, nobody can process it!
return;
}

View File

@@ -230,7 +230,7 @@ bool RF95Interface::reconfigure()
err = lora->setPreambleLength(preambleLength);
if (err != RADIOLIB_ERR_NONE)
LOG_ERROR(" RF95 setPreambleLength %s%d", radioLibErr, err);
LOG_ERROR("RF95 setPreambleLength %s%d", radioLibErr, err);
assert(err == RADIOLIB_ERR_NONE);
err = lora->setFrequency(getFreq());

View File

@@ -140,7 +140,7 @@ const RegionInfo regions[] = {
Philippines
433 - 434.7 MHz <10 mW erp, NTC approved device required
868 - 869.4 MHz <25 mW erp, NTC approved device required
915 - 918 MHz <250 mW EIRP, no external antennna allowed
915 - 918 MHz <250 mW EIRP, no external antenna allowed
https://github.com/meshtastic/firmware/issues/4948#issuecomment-2394926135
*/
@@ -271,7 +271,7 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr)
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
delay = random(0, 2 * CWsize) * slotTimeMsec;
LOG_DEBUG("rx_snr found in packet. As a router, setting tx delay:%d", delay);
LOG_DEBUG("rx_snr found in packet. Router: setting tx delay:%d", delay);
} else {
// offset the maximum delay for routers: (2 * CWmax * slotTimeMsec)
delay = (2 * CWmax * slotTimeMsec) + random(0, pow(2, CWsize)) * slotTimeMsec;
@@ -346,7 +346,7 @@ bool RadioInterface::reconfigure()
bool RadioInterface::init()
{
LOG_INFO("Starting meshradio init...");
LOG_INFO("Start meshradio init");
configChangedObserver.observe(&service->configChanged);
preflightSleepObserver.observe(&preflightSleep);
@@ -494,7 +494,7 @@ void RadioInterface::applyModemConfig()
}
if ((myRegion->freqEnd - myRegion->freqStart) < bw / 1000) {
static const char *err_string = "Regional frequency range is smaller than bandwidth. Falling back to default preset.";
static const char *err_string = "Regional frequency range is smaller than bandwidth. Fall back to default preset";
LOG_ERROR(err_string);
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
@@ -578,7 +578,7 @@ void RadioInterface::limitPower()
maxPower = myRegion->powerLimit;
if ((power > maxPower) && !devicestate.owner.is_licensed) {
LOG_INFO("Lowering transmit power because of regulatory limits");
LOG_INFO("Lower transmit power because of regulatory limits");
power = maxPower;
}
@@ -598,11 +598,9 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
{
assert(!sendingPacket);
// LOG_DEBUG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
// LOG_DEBUG("Send queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag); // It should have already been encoded by now
lastTxStart = millis();
radioBuffer.header.from = p->from;
radioBuffer.header.to = p->to;
radioBuffer.header.id = p->id;

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