Compare commits

...

247 Commits

Author SHA1 Message Date
Ric In New Mexico
57542ce9e6 Retain device nodeinfo during reset-nodedb (#2951)
* INA3221 bugfixes & refinement
Reorganized and refactored some INA3221 code
Added comments
Added missing shunt resistor value (100mΩ)
Added INA3221 Channel 1 to getINAVoltage() for device battery monitoring
	modified:   src/Power.cpp
	modified:   src/modules/Telemetry/PowerTelemetry.cpp
	modified:   src/modules/Telemetry/Sensor/INA3221Sensor.cpp
	modified:   src/modules/Telemetry/Sensor/INA3221Sensor.h
	modified:   src/power.h

* reset-nodedb retain device nodeinfo
	modified:   src/mesh/NodeDB.cpp

* reset-nodedb #2
	modified:   src/mesh/NodeDB.cpp

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2023-11-20 06:33:14 -06:00
Jonathan Bennett
1b20a82b55 Update package_raspbian.yml
Trunk
2023-11-19 20:28:37 -06:00
Jonathan Bennett
195706e0e5 Update package_raspbian.yml to pull correct code for PR runs 2023-11-19 20:19:43 -06:00
Jonathan Bennett
c1f5878648 Add Raspbian to firmware zip 2023-11-19 17:11:54 -06:00
Jonathan Bennett
7380f3b170 Trunk fmt fix whitespace 2023-11-19 16:53:00 -06:00
Jonathan Bennett
a9d846c1b3 make package_raspbian.yml a reusable workflow 2023-11-19 16:45:06 -06:00
Jonathan Bennett
cfb09ee115 add .deb to release 2023-11-19 16:41:47 -06:00
Jonathan Bennett
8f0ce606db Update package_raspbian.yml upload .deb as artifact 2023-11-19 16:07:08 -06:00
Jonathan Bennett
d04ff29c2a Update package_raspbian.yml use ubuntu-latest 2023-11-19 15:56:41 -06:00
Jonathan Bennett
8e92754b59 Update package_raspbian.yml 2023-11-19 15:48:43 -06:00
Jonathan Bennett
dad824c0e9 Update package_raspbian.yml -- add checkout step 2023-11-19 15:16:11 -06:00
Jonathan Bennett
31d7c6826d Update package_raspbian.yml
Properly run build_raspbian as a step
2023-11-19 15:03:46 -06:00
Jonathan Bennett
d33521ee86 Add package-raspbian workflow 2023-11-19 14:53:49 -06:00
Jonathan Bennett
5ad12fed60 Chill out, yamllint 2023-11-19 14:53:49 -06:00
Jonathan Bennett
4af90eeb39 Revamp yaml config for Raspbian 2023-11-19 14:53:49 -06:00
Jonathan Bennett
08297bb0b7 Copy and Paste output file location for workflow 2023-11-18 15:36:41 -06:00
Jonathan Bennett
16ef40b21f Add even moar workflow debugging 2023-11-18 15:16:36 -06:00
Jonathan Bennett
7ef4abb974 Add debugging output to main workflow 2023-11-18 14:56:40 -06:00
Jonathan Bennett
297267d037 Try harder to find Raspbian binary 2023-11-18 13:26:05 -06:00
Jonathan Bennett
f8e766ebc7 Include Raspbian in release zip 2023-11-18 12:05:51 -06:00
Jonathan Bennett
7bd2b07024 Disable radiolib debug 2023-11-18 12:05:51 -06:00
Jonathan Bennett
b6ddbd0087 More CI work for Raspbian (#2949)
* More CI work for Raspbian

* Workaround quirks of Arm64/debian runners
2023-11-18 11:04:21 -06:00
Jonathan Bennett
dc8903ec42 Add Raspbian to Main CI (#2948) 2023-11-18 08:55:19 -06:00
Ben Meadors
46bd6ca7ba YAML based config for PI / Portduino (#2943)
* Add configuration via /etc/meshtastic/config.yaml

* Move example config, support more locations

* Fix config check

* Use access() to check for config file presence

* Throw an error and exit on radio init fail

* Adds error check for reading Bluetooth MAC

* Settle on meshtasticd, add install script

* Shell fixes

* Fine. I'll put it back and then disable you

* Get wrekt, shellchekt

* Firat attempt at adding raspbian CI build

* Tickle the workflow

* Beatings will continue til morale improves

* Permissions are overrated

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2023-11-18 08:12:34 -06:00
Ric In New Mexico
9d4af1146e INA3221 bugfixes & refinement (#2944)
Reorganized and refactored some INA3221 code
Added comments
Added missing shunt resistor value (100mΩ)
Added INA3221 Channel 1 to getINAVoltage() for device battery monitoring
	modified:   src/Power.cpp
	modified:   src/modules/Telemetry/PowerTelemetry.cpp
	modified:   src/modules/Telemetry/Sensor/INA3221Sensor.cpp
	modified:   src/modules/Telemetry/Sensor/INA3221Sensor.h
	modified:   src/power.h
2023-11-17 06:46:59 -06:00
Thomas Göttgens
5ce6ca25f2 Merge pull request #2083 from meshtastic/raspi-portduino
Start working on RF95 attached to Raspberry Pi
2023-11-16 15:07:02 +01:00
Ben Meadors
f2210d8f8d Merge branch 'master' into raspi-portduino 2023-11-16 06:57:52 -06:00
Ben Meadors
5d917885df Added Remove node by nodenum admin message (#2941)
* Remove node by nodenum

* It were backerds! DERP
2023-11-16 06:57:22 -06:00
Jonathan Bennett
e99ae64ece Add Pi library only to Raspbian 2023-11-15 21:16:27 -06:00
Jonathan Bennett
61f888e952 Add missed ifdef 2023-11-15 21:01:17 -06:00
Jonathan Bennett
a144d5d6cc Clean up, fix reboot, minimize changes 2023-11-15 20:33:53 -06:00
Ben Meadors
c3e3569c14 Merge branch 'master' into raspi-portduino 2023-11-15 19:39:19 -06:00
Jonathan Bennett
b1b5bafdda Add PiHal and get Waveshare SX1262 XXXM working 2023-11-15 17:04:41 -06:00
Ben Meadors
91e399a2b6 Added detection sensor en pin to fix issues with RAK microwave (#2940) 2023-11-15 09:26:47 -06:00
HookdomPonix
8b16367597 Add support for the rak10701 board, no touch (#2933)
* Add support for the rak10701 board, no touch

* Moved tftblack fillin and changed teh src flags

* Added rak10701 to platformio.ini

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-11-13 06:20:49 -06:00
S5NC
0b9accc3b6 Remove redundant checks for power of 0 (#2934)
* Add comment explaining necessity for second 0 check

Thank you @GUVWAF

* Update RF95Interface.cpp

* Update STM32WLE5JCInterface.cpp

* Update SX126xInterface.cpp

* Update SX128xInterface.cpp

* remove whitespace...

* Update SX128xInterface.cpp
2023-11-13 06:19:02 -06:00
GUVWAF
590b0bbff4 Merge pull request #2935 from S5NC/add-missing-has-sensor
Add missing defaulting for HAS_SENSOR to configuration.h
2023-11-10 09:57:44 +01:00
S5NC
19be230b24 Update configuration.h 2023-11-08 21:58:33 +00:00
Jonathan Bennett
8df16ad6a6 Add ctime include to fix native compile 2023-11-08 14:36:12 -06:00
Ben Meadors
2d62f00ac3 Merge branch 'master' into raspi-portduino 2023-11-08 09:54:18 -06:00
pdxlocations
9f93b9ab9d fix sizeof error 2023-11-08 12:40:51 +01:00
pdxlocations
fc3200134d party time 2023-11-08 12:40:51 +01:00
Ben Meadors
470264b7f9 Merge branch 'master' into raspi-portduino 2023-11-07 05:58:42 -06:00
Ben Lipsey
600541ac25 Fix Documentation Links in Comments (#2929)
* update external notification

* ContentHandler
2023-11-06 22:03:44 +00:00
github-actions[bot]
298b383127 [create-pull-request] automated change (#2927)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-11-05 06:50:02 -06:00
Ric In New Mexico
f57020412e INA3221 / Power Telemetry Payload Variant Implementation (#2916)
* INA3221 / Power Telemetry Variant Implementation
	modified:   platformio.ini
	modified:   src/configuration.h
	modified:   src/detect/ScanI2C.h
	modified:   src/detect/ScanI2CTwoWire.cpp
	modified:   src/main.cpp
	modified:   src/modules/Modules.cpp
	new file:   src/modules/Telemetry/PowerTelemetry.cpp
	new file:   src/modules/Telemetry/PowerTelemetry.h
	new file:   src/modules/Telemetry/Sensor/INA3221Sensor.cpp
	new file:   src/modules/Telemetry/Sensor/INA3221Sensor.h
	modified:   src/mqtt/MQTT.cpp

* ifdef for portduino / linux native
	modified:   src/modules/Telemetry/PowerTelemetry.cpp

* try #2
	modified:   src/modules/Modules.cpp
	modified:   src/modules/Telemetry/PowerTelemetry.cpp
	deleted:    variants/xiao_ble/1.0.0/libraries/SPI/SPI.cpp

* try #3
	modified:   src/modules/Modules.cpp

* try #4
	modified:   src/modules/Telemetry/PowerTelemetry.cpp

* try #5?
	modified:   src/modules/Telemetry/PowerTelemetry.cpp

* try #6
	modified:   src/modules/Telemetry/PowerTelemetry.cpp

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-11-04 20:07:00 -05:00
Ben Meadors
4a6cc8fd8c Extend packet history expire time to 10 minutes (#2921) 2023-11-03 15:43:26 -05:00
Tyler Jang
45c5e0e730 cleanup disables (#2924)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-11-03 06:50:30 -05:00
github-actions[bot]
527bffb7e0 [create-pull-request] automated change (#2926)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-11-03 06:36:24 -05:00
GUVWAF
4c35a7fb7d Handle AmbientLighting Module config (#2923) 2023-11-03 07:36:36 +00:00
GUVWAF
0f9936a0e0 Change default Coding Rate to 4/5 for <=LongFast (#2920)
Increases througput at the cost of a little bit of sensitivity
Non-breaking as the CR is sent in the LoRa header
2023-11-02 09:21:07 -05:00
Thomas Göttgens
40395bef01 Merge branch 'master' into raspi-portduino 2023-10-31 14:09:38 +01:00
GUVWAF
8b8fffda81 Drop packets if toPhoneQueue is full, unless it's text/RangeTest (#2918) 2023-10-30 06:12:22 -05:00
Ric In New Mexico
4052194dfe Fix for is_licensed save / reboot (#2911)
* Fix is_licensed save / reboot

* Revert "Fix is_licensed save / reboot"

This reverts commit 634151b8ec.

* Changed reloadConfig to saveChanges /w reboot
2023-10-26 06:25:06 -05:00
Ben Meadors
b36ffe5200 Trunk fmt fix 2023-10-24 18:52:46 -05:00
S5NC
a60b4d08bf Hydra variant rectification (#2903)
* Update variant.h

* Update variant.h

* Update platformio.ini
2023-10-24 18:47:36 -05:00
github-actions[bot]
227467f638 [create-pull-request] automated change (#2897)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-10-20 09:52:56 -05:00
Tavis
092e6f2424 add rssi and snr to json output (#2894)
* add rssi and snr to json output

* explicitly cast to int and float
2023-10-17 06:50:36 -05:00
Andre K
e6b20bff77 refactor: simplify MQTT defaults (#2893)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-10-15 18:56:47 -05:00
Andre K
2c625f6ba1 fix: channel routing for decoded MQTT packets (#2892)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-10-15 06:41:40 -05:00
Manuel
142d56c663 allow sensors connected to second I2C port (#2891) 2023-10-14 19:33:45 -05:00
Ben Meadors
f4b40562d3 Start of TAK role (#2890)
* Start of TAK role

* Position flags change for CoT friendly altitudes

* Trunk
2023-10-14 06:49:38 -05:00
github-actions[bot]
9e203532d0 [create-pull-request] automated change (#2889) 2023-10-13 20:02:59 -05:00
code8buster
8bd7b5e779 Merge pull request #2887 from yupyvovarov/fix-hwids-address
Fix typo in tbeam-s3-core hwids address
2023-10-13 10:24:49 +00:00
Yurii Pyvovarov
1af970765f Fix typo in tbeam-s3-core hwids address 2023-10-13 11:31:10 +03:00
Ben Meadors
def55ec063 Remove specific upload ports from pio 2023-10-11 10:21:58 -05:00
Ben Meadors
092c6cac66 Convert from inline to static class methods (#2883) 2023-10-11 06:17:05 -05:00
Ben Meadors
e39f129bd6 More comprehensively clear current position info (#2881) 2023-10-10 19:33:58 -05:00
S5NC
9d1fe8c245 Update architecture.h (#2880) 2023-10-10 15:35:07 -05:00
Aciid
786248a6b1 Dragino TrackerD wip (#2324)
* Dragino TrackerD initial variant

* fmt

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-10-10 06:20:46 -05:00
github-actions[bot]
d1ac2dc6ea [create-pull-request] automated change (#2879)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-10-09 20:43:42 -05:00
Ben Meadors
87396d9105 Refactor away some code duplication in screen frames and display formatter for modem presets (#2872)
* Refactor away some duplication

* Refactor preset names to display formatter method

* Remove unused screen brightness adjustment and extract wifi disconnect reason name to display formatter method

* Tronk

* Let's be more clear with this naming

* Effed

* DisplayFormatters static class and use native wifi disconnect reason names method

* git mv file so casing should match now

* Include titlecase

* Trunk
2023-10-09 20:43:16 -05:00
Ben Meadors
b388f8edcd Merge branch 'master' into raspi-portduino 2023-10-09 19:45:08 -05:00
Ben Meadors
10265aabd5 Fix buggy phone positions (#2876)
* Guard-clause channel util. to reduce nesting

* Try-fix PhoneAPI position not updating

* Trunk

* Missed it

* Really disable GPS when asked to

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2023-10-09 18:33:04 -05:00
Jonathan Bennett
8780d93941 Remove missed GPS definition (#2878) 2023-10-09 13:30:51 -05:00
Sacha Weatherstone
54f0c045e4 Update README.md 2023-10-09 22:30:02 +10:00
github-actions[bot]
3ddad671a5 [create-pull-request] automated change (#2875)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-10-08 08:12:42 -05:00
pat-trunk-io
dc6f0b8e0b mention trunk is beta on windows (#2871)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-10-06 15:31:04 -05:00
pat-trunk-io
33f28c3d56 Add trunk githooks to the repo (#2870) 2023-10-06 15:02:27 -05:00
github-actions[bot]
ef1d8c8eee [create-pull-request] automated change (#2869) 2023-10-05 17:51:23 -05:00
Ben Meadors
950d5f0946 Power saving sensor (#2865)
* Trunk

* Again

* This thing just keeps updating itself

* Ignore tools

* Sleepy sensor

* Batrunkadunk
2023-10-05 12:42:03 -05:00
Thomas Göttgens
fc06754e1f Possibly fix #2704 "Heltec Wireless Tracker screen doesn't display anything" (#2749)
* fix #2704


Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2023-10-04 22:24:25 -05:00
github-actions[bot]
fbf74fc0b2 [create-pull-request] automated change (#2863)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-10-04 10:23:55 -05:00
code8buster
7cebd79475 Use doNotEnterOff flag to prevent GNSS poweroff before fix acquisition (#2861)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-10-03 19:50:27 -05:00
Jonathan Bennett
aa38f53aed Fix for T-Beam 1.2 GPS (#2858)
* Fix for T-Beam 1.2 GPS, with DEBUG enabled

* Don't break other devices

* Saving GPS data on this breaks on next boot. Fix.

* derp

* disable the extra verbosity

* Try the same sort of factory reset as the Lilygo image

* Catch GPS reboots and squash

* trunk

* GPS

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-10-03 12:05:40 -05:00
Ben Meadors
2a6c8be684 Avoid problematic sleep state transitions for power saving sensors and trackers (#2860)
* Avoid problematic sleep state transitions for power saving sensors and trackers

* Line got duped :-|
2023-10-03 10:09:27 -05:00
GUVWAF
37c3d15978 Check if packet is decrypted before using portnum when converting to JSON (#2857)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-10-03 06:39:35 -05:00
Manuel
f301e236eb fix crash during shutdown (#2859)
* fix null pointer access

* ptr initialize
2023-10-03 06:37:46 -05:00
Manuel
94c2ade272 make esp32 deepsleep button wakeup functional again (#2854)
* make deepsleep button wakeup functional again

* Remove unused var

* Cleanup comment

* suppress screen wake on button

* add resume screen

* trunk fmt

* added missing #ifdef

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-10-02 16:16:29 -05:00
Ben Meadors
a6e4402e41 Screen on secs router default (#2855) 2023-10-02 06:28:05 -05:00
Jonathan Bennett
50db2d0e9b Add timeout to ublox PMREQ command (#2851) 2023-10-01 20:39:18 -05:00
Ben Meadors
5ecdbd0dbb Removed non-functional deep sleep button awake functionality (user can RST instead) (#2852)
* Fixed mask length

* Don't want_response if we're a tracker or sensor

* Fixes

* Removing non-functioning deep sleep button awake
2023-10-01 12:48:12 -05:00
Jonathan Bennett
47c6738c0d Fix GPS init bug -- power up even when disabled (#2850) 2023-09-30 23:38:51 -05:00
Ben Meadors
1552aa0081 Tracker role wakeup and sleep cycle when power.is_power_saving true (#2846)
* WIP

* Sleepy sleepy low power tracker

* Sleepy tracker clear

* NRF52 PoC

* Simplify NRF52 "sleep"

* Trackers aren't polite

* Remove unnecessary include

* Removed accidental commit

* Fixed not-so-sleepy T-Beam due to button gpio mask precendence

* Added sleepOnNextExecution for allowing fulfillment of pending messages before shutting down

* Cleanup

* Don't wantResponse for trackers

* Heltec wireless tracker doesn't like the button interrupt (maybe all s3 because user button press doubles as bootloader mode trigger?)
2023-09-30 21:09:17 -05:00
github-actions[bot]
6ebec8fcd9 [create-pull-request] automated change (#2849)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-30 20:40:04 -05:00
Manuel
e9215a5d70 revert KB_POWERON changes (#2847) 2023-09-30 06:43:36 -05:00
Thomas Göttgens
5075849ec0 Add missing endif 2023-09-28 10:50:26 +02:00
Thomas Göttgens
7f16b6b342 Merge branch 'master' into raspi-portduino 2023-09-28 09:29:45 +02:00
S5NC
4e3576ae48 Simplify SX126x variant configuration (#2813)
* Update SX126xInterface.cpp

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update SX126xInterface.cpp

* Update SX126xInterface.cpp

* Update variant.h

* Update variant.h

* trunk fmt

* trunk fmt

* Update variant.h

* trunk fmt

* trunk fmt

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update pins_arduino.h

* Update pins_arduino.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* trunk fmt

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* trunk fmt

* trunk fmt

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

Specify behavior

* Update variant.h

Maintain behavior

* trunk fmt

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-27 16:01:40 -05:00
Tavis
98290e5d7b Re issue: #2496 Populate the position log entries from PositionModule with data fields (#2839)
* Populate the position log entries with data fields

includes datafields with no data as 0

* trunk check formatted.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-27 16:00:56 -05:00
Ben Meadors
ad529924f1 Code duplication cleanup for smart position logic (#2840) 2023-09-27 10:32:35 -05:00
github-actions[bot]
07d51a2ca4 [create-pull-request] automated change (#2837) 2023-09-26 14:54:35 -05:00
github-actions[bot]
47301a5ac0 [create-pull-request] automated change (#2836)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-26 11:11:54 -05:00
Ben Meadors
0d023ea215 Revert "Fix compression (#2806) (#2819)" (#2835)
This reverts commit cdac643749.
2023-09-26 07:02:06 -05:00
Ben Meadors
b5e952db24 No more goober traffic on public mqtt (#2831)
* No more goober traffic on public mqtt

* Oops
2023-09-26 06:19:17 -05:00
GUVWAF
a1c433748a RP2040: Add SerialModule support (#2830)
* Support for SerialModule on RP2040

* Remove one !defined too many

* Increase serial RX_BUFFER: more reliable for long packets
Even results into an error for ESP32

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-26 05:45:34 -05:00
Jonathan Bennett
04b2ab82dc Add GPS pin definitions missed in revamp (#2834) 2023-09-26 05:44:08 -05:00
github-actions[bot]
e96ba7cbcf [create-pull-request] automated change (#2827)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-25 06:31:22 -05:00
Andre K
61f6fb22c5 move STATE_SEND_METADATA to beginning of wantConfig (#2820)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-24 07:22:54 -05:00
github-actions[bot]
db7b77c76e [create-pull-request] automated change (#2823)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-24 07:01:46 -05:00
Andre K
350090ec0d remove residual code for mesh_sds_timeout_secs (#2821)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-24 06:49:35 -05:00
GUVWAF
cdac643749 Fix compression (#2806) (#2819)
* Fix compression: encode to bytes after `decoded` is modified

* Change payload size to decompressed length

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-24 06:49:21 -05:00
Jonathan Bennett
1a2c7f00e1 Gps cleanup and powersave (#2807)
* Refactor GPS to not probe if pins not defined

* Use Named Constructor to clean up code

* Move doGPSPowerSave to GPS class

* Make sure to set GPS awake on triple-click

* Cleanup and remove dead code

* Rename GPS_PIN_WAKE to GPS_PIN_STANDBY

* Actually put GPS to sleep between fixes

* add GPS_POWER_TOGGLE for heltec-tracker and t-deck

* Change GPS_THREAD_INTERVAL to 200 ms

* More dead code, compiler warnings, and add returns

* Add Number of sats to log output

* Add pgs enable and triple-click config

* Track average GPS fix time to judge low-power time

* Feed PositionModule on GPS fix

* Don't turn off the 3v3_s line on RAK4631
when the rotary is present.

* Add GPS power standbyOnly option

* Delay setting time currentQuality
to avoid strange log message.

* Typos, comments, and remove unused variable

* Short-circuit the setAwake logic on GPS disable

* heltec-tracker 0.3 GPS power saving

* set en_gpio to defined state

* Fix fixed_position logic with GPS disabled

* Don't process GPS serial when not isAwake

* Add quirk for Heltec Tracker GPS powersave

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: mverch67 <manuel.verch@gmx.de>
Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com>
2023-09-23 23:45:35 -05:00
Jonathan Bennett
7eff5e7bcb Fix for Pi Pico hang (#2817)
* Fix for Pi Pico hang

* Pi Pico fix part 2: Electric Boogaloo
2023-09-20 19:34:45 -05:00
Jonathan Bennett
17207681ef Remove GPS pins from devices lacking built-in GPS (#2812) 2023-09-19 10:55:14 -05:00
Thomas Göttgens
94f7c7e472 Merge pull request #2814 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2023-09-19 12:46:26 +02:00
caveman99
0a12d67d19 [create-pull-request] automated change 2023-09-19 10:45:28 +00:00
Thomas Göttgens
3175a3d630 Merge pull request #2811 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2023-09-19 10:48:41 +02:00
thebentern
4e9bf75340 [create-pull-request] automated change 2023-09-18 19:49:42 +00:00
github-actions[bot]
e8970ad66b [create-pull-request] automated change (#2810)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-18 13:26:09 -05:00
code8buster
f737ee59ec Deny maxhops to anyone who sets >7 (#2808)
* Deny maxhops to anyone who sets >7

* Use reliable hop count instead of 3
2023-09-18 12:58:09 -05:00
Ric In New Mexico
6d211815d9 Temp fix for S3 bluetooth (#2809)
Need to roll back espressif to v6.3.2
2023-09-18 14:26:19 +02:00
Manuel
1bae926576 fix: nodenum 4 (#2798)
* tryfix: nodenum 4

* trunk fmt

* rename vars and fix brackets

* purge invalid db entries

* trunk fmt
2023-09-18 06:16:37 -05:00
Thomas Göttgens
a1514b8b64 Enable (new) ADC and GPS capability. (#2792)
* Enable (new) ADC and GPS capability.
* Make Picomputer a canon device and define ADC for new board revision
2023-09-18 11:38:33 +02:00
Jonathan Bennett
8b82ae6fe3 refactor and avoid needless probe (#2799)
* Use UINT32_MAX to indicate no configured GPS

* Refactor GPS to not probe if pins not defined

* Minor cleanups related to rework

* Use Named Constructor to clean up code

* Actually disable the GPS thread

* Don't actually disable the GPS thread

* Move doGPSPowerSave to GPS class

* Make sure to set GPS awake on triple-click

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-16 23:10:10 -05:00
Ric In New Mexico
822c150e0d Fixing typo in src/mesh/mesh-pb-constants.cpp logging (#2800)
* Update variant.h

Add second i2c channel on external connector for Station G1

* Create trunk-check.yml

* Fix typo in logging

Corrected typo in pb_msgdesc logging for packets failing to be decoded.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-16 15:24:59 -05:00
github-actions[bot]
0731902744 [create-pull-request] automated change (#2791)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-12 18:00:29 -05:00
github-actions[bot]
b53cb38a09 [create-pull-request] automated change (#2790)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-12 16:50:52 -05:00
Jonathan Bennett
b02dd0e964 Move partial GPS initialization earlier in boot (#2788)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-12 16:46:46 -05:00
Ben Meadors
c608f0ba81 Fix time=0 bug for fixed_position nodes (#2789) 2023-09-12 15:54:50 -05:00
Jonathan Bennett
e1839e33f2 Lazy probe of GPS (#2781)
* First attempt at lazy config of GPS

* More GPS rework
Break GPS init into smaller, interruptable steps
Move more GPS commands into ubx.h
Combine Setup functions

* Move the rest of UBX messages to ubs.h
2023-09-10 22:21:14 -05:00
Manuel
d6d51bc3f4 T-Deck/T-Watch: enhancements/fixes (#2786)
* T-Deck: enhancements/fixes

* trunk fmt

* T-Watch board update

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-10 06:54:25 -05:00
github-actions[bot]
44a77a10e1 [create-pull-request] automated change (#2785)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-10 06:34:48 -05:00
Ben Meadors
8255128eae Trunk finally spilled the beans about what it's upset about 2023-09-09 19:40:57 -05:00
Ric In New Mexico
d7a98519f4 Update variant.h (#2778)
* Update variant.h

Add second i2c channel on external connector for Station G1

* Create trunk-check.yml

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-09 19:37:35 -05:00
github-actions[bot]
e256520336 [create-pull-request] automated change (#2782)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-08 14:34:58 -05:00
Ben Meadors
fcf798df98 Experiment with moving gps init (#2780)
* Move it move it

* Moving to the end of the main setup method

* NimBLE version
2023-09-07 16:01:35 -05:00
Ben Meadors
dcdf9b64de Ambient lighting (#2779)
* This was already defined and throwing a ton of warnings

* Ambient lighting module feature

* Use local instance type
2023-09-07 12:24:47 -05:00
Jonathan Bennett
fd563e41f1 Add ubx-cfg-rxm and cfg-pm2 for ublock 6 powersave (#2777) 2023-09-07 12:24:21 -05:00
Jonathan Bennett
0fa3685161 Fix crash in GPS setup when GPS is disabled 2023-09-06 12:38:58 -05:00
code8buster
899f9dd7bf Merge pull request #2775 from GUVWAF/disabledNeighbor
Only update neighbors when module is enabled
2023-09-05 23:43:09 +00:00
GUVWAF
9af4ecf48f Remove unnecessary line when disabled 2023-09-05 21:42:39 +02:00
GUVWAF
cfb6a1394c Only update neighbors when module is enabled 2023-09-05 19:56:42 +02:00
code8buster
1254031f7d Merge pull request #2772 from meshtastic/ubx-pmreq
UBX-RXM-PMREQ soft-off implemented
2023-09-05 17:15:12 +00:00
code8buster
c91e306659 Move packet scratch declaration to header 2023-09-05 11:59:34 -04:00
code8buster
4ff343b20f no byte... just 8 unsigned bits please 2023-09-05 00:32:53 -04:00
code8buster
134fc75b67 UBX-RXM-PMREQ soft-off implemented 2023-09-05 00:26:42 -04:00
Ben Meadors
fb23e479ac Update ESP32 platform (#2770) 2023-09-04 20:20:20 -05:00
github-actions[bot]
5a61695016 [create-pull-request] automated change (#2769)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-04 19:45:46 -05:00
github-actions[bot]
3bcab0e223 [create-pull-request] automated change (#2768)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-04 18:38:58 -05:00
GUVWAF
17617ce031 Fix possible memory leak in NeighborInfo Module (#2765)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-04 18:38:16 -05:00
Jonathan Bennett
97f0c734e0 Fix Neighborinfo crash
neighbors object wasn't initialized when module disabled, this
initializes it to a safe, empty object.
2023-09-04 18:15:27 -05:00
Jonathan Bennett
e943fffe8c GPS fixes
Work aroung Serial reset issue on ESP32
Don't send unsupported command to G60xx GPS
2023-09-04 15:00:05 -05:00
tropho23
ffcb131171 GPS toggle for RAK4631 (patch 2 of 2) (#2764)
* Added triple-press GPS toggle button changes

* Revert edits to extensions.json

* comma'd

* Update variant.h

Added the line:

// Define pin to enable GPS toggle (set GPIO to LOW) via user button triple press
#define PIN_GPS_EN 34 // GPS power enable pin

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: code8buster <communismisgreat@national.shitposting.agency>
2023-09-04 13:17:01 -05:00
tropho23
bb1fe7cad3 GPS toggle for RAK4631 (patch 1 of 2) (#2763)
* Added triple-press GPS toggle button changes

* Revert edits to extensions.json

* comma'd

* Update platformio.ini

Added line:

-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: code8buster <communismisgreat@national.shitposting.agency>
2023-09-04 13:16:39 -05:00
Ben Meadors
ad40493a39 Add speed, heading, and DOP to default position flags (#2759)
* Add speed and heading

* Add DOP
2023-09-04 06:46:27 -05:00
Jonathan Bennett
ac62330e1c Found lost byte dropped from moduleinfo
Attempt to fix CFG-GNSS for neo-6m
2023-09-03 22:38:03 -05:00
code8buster
53f6a43661 Merge pull request #2752 from meshtastic/nmea-rate
Adds GPS Serial Speed scanning, fixes ublox GNSS setup errors
2023-09-03 21:57:51 +00:00
Jonathan Bennett
7ad94da1c6 Add more to GPS_DEBUG and fix ubx7 CFG-GNSS 2023-09-03 16:20:01 -05:00
Jonathan Bennett
ecdb75aae0 Correct UBX-CFG-PMS message 2023-09-03 02:16:29 -05:00
Jonathan Bennett
7c98445ca3 Cleanup in prep for commiting
Fix some compilation warnings
gate debug code behind GPS_DEBUG
minor fix in u-blox protocol detection
Begin to gate GPS messages based on protover
2023-09-03 01:50:11 -05:00
Jonathan Bennett
b21368ecfa Add delay and debug code for GPS probe 2023-09-02 20:35:38 -05:00
Jonathan Bennett
1a178c7d33 Add check for GPS Frame Errors message 2023-09-02 04:29:48 -05:00
Jonathan Bennett
5d6f0ea6c4 Fix possible edge case in GPS detection 2023-09-01 16:24:28 -05:00
Ben Meadors
5bd861f3d8 Merge branch 'master' into nmea-rate 2023-09-01 15:08:32 -05:00
GUVWAF
6d93fab495 Add neighbor IDs to MQTT JSON (#2756)
* Add neighbor IDs to JSON

* Limit #neighbors to what we can actually save

* Put neighbor IDs in an array

* Add SNR to neighbors in nested objects
2023-09-01 14:35:57 -05:00
Jonathan Bennett
6803fd7949 More fixes for GPS chips with unexpected baud 2023-09-01 12:11:39 -05:00
Jonathan Bennett
a61f969773 Increase GPS detection timeout slightly 2023-08-31 22:19:50 -05:00
Jonathan Bennett
79cfc4b725 Avoid Serial output mangling with RTOS. 2023-08-31 20:40:01 -05:00
Jonathan Bennett
cf762bbd42 Cut down delay times for GPS probe and init 2023-08-31 20:39:23 -05:00
code8buster
3d2c419d0d Remove leftover debug msg 2023-08-30 16:24:56 -04:00
Jonathan Bennett
903f619609 Add GPS serial speed scan 2023-08-28 19:01:14 -05:00
Jonathan Bennett
2e3f762d3d Catch a nullptr return rather than crash 2023-08-28 04:05:45 -05:00
Jonathan Bennett
a42266f74b GPS: Fix checksum and remove spurious returns 2023-08-28 04:05:45 -05:00
github-actions[bot]
a605c69eb4 [create-pull-request] automated change (#2748)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-08-26 07:36:04 -05:00
Thomas Göttgens
282cc0b16a Merge pull request #2737 from meshtastic/BBQ10Kb-Fix
Bbq10 kb fix
2023-08-26 11:22:35 +02:00
Thomas Göttgens
4ab67f3668 IGOR! Fetch me the brain! 2023-08-25 16:44:39 +02:00
Thomas Göttgens
312028b161 Possble fix ESC 2023-08-25 09:27:09 +02:00
Ben Meadors
ecd48db69c Merge branch 'master' into BBQ10Kb-Fix 2023-08-24 19:57:49 -05:00
Ben Meadors
03dc36ea12 Use fixed position regardless of gps lock (#2744) 2023-08-24 10:55:49 -05:00
Mark Trevor Birss
c2ae38405e Update architecture.h (#2746) 2023-08-24 07:58:24 -05:00
Thomas Göttgens
2a1d8c40b4 add TAB and ESC handling 2023-08-24 14:24:26 +02:00
Ben Meadors
e2441c425a Merge branch 'master' into BBQ10Kb-Fix 2023-08-24 07:06:42 -05:00
Mark Trevor Birss
00ffe73ebd Heltec ESP32-C3 HT-CT62 support (#2741)
* Add files via upload

* Update platformio.ini

* Update variant.h

* Update platformio.ini

* Switch to our new HW_MODEL

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Ben Meadors <thebentern@tuta.io>
2023-08-23 07:59:21 -05:00
Thomas Göttgens
3355019de3 Merge branch 'master' into BBQ10Kb-Fix 2023-08-23 09:45:06 +02:00
Thomas Göttgens
5bb207d88b reset sym after second keypress
also remove debug print and non-working scancodes.
2023-08-23 09:44:20 +02:00
github-actions[bot]
5453e4d123 [create-pull-request] automated change (#2742)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-08-22 17:11:22 -05:00
Thomas Göttgens
7f1b58a222 trunk fmt 2023-08-22 21:23:37 +02:00
Thomas Göttgens
39357b2686 Merge branch 'BBQ10Kb-Fix' of github.com:meshtastic/firmware into BBQ10Kb-Fix 2023-08-22 21:23:00 +02:00
Thomas Göttgens
d6b629ae04 update SYM Scancode 2023-08-22 21:19:51 +02:00
Thomas Göttgens
7b1aeb60cd Try manual scancode for SYM 2023-08-22 21:19:51 +02:00
Thomas Göttgens
5c7c1cd253 silence compiler warnings 2023-08-22 21:19:51 +02:00
Thomas Göttgens
8cfe130df3 update SYM Scancode 2023-08-22 21:11:19 +02:00
Thomas Göttgens
feef86942d Merge pull request #2738 from meshtastic/neighbourinfo-fix
fix crash and Debug logging in NeighbourInfo
2023-08-22 16:27:52 +02:00
Thomas Göttgens
5f3a8b4924 fix crash and Debug logging in NeighbourInfo 2023-08-22 15:43:21 +02:00
Thomas Göttgens
0fcaaf39b0 Try manual scancode for SYM 2023-08-22 11:23:19 +02:00
Thomas Göttgens
a55eac5c20 silence compiler warnings 2023-08-22 10:58:54 +02:00
github-actions[bot]
b47c9c165a [create-pull-request] automated change (#2733)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-08-19 18:06:33 -05:00
Thomas Göttgens
ecceb10910 different debug print 2023-08-19 21:28:02 +02:00
Thomas Göttgens
6fc76103a0 temporarily Enable debug print 2023-08-19 20:55:50 +02:00
Ben Meadors
f35c7be917 Just putting back DELAYED_INTERVAL for reliability. Ran into problems 2023-08-19 09:45:48 -05:00
Ben Meadors
364364263b Remove range_test goalie from drawing frames 2023-08-19 09:44:40 -05:00
Manuel
ef957bfac5 support BB Q10 keyboard (#2703)
* support BB Q10 keyboard

* remove debug code

* fix wrong logic

* fix left/right keys for cardkb

* Try to enable Q10 kb after all

* cppcheck

* Only fire on Key release and assume 0x0a is a enter as well

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2023-08-19 08:37:42 -05:00
Ben Meadors
5d78795065 Portnum promiscuity for text messages from other modules (#2732)
* Add interested portnums to TextMessageModule

* Send Detection Sensor Module messages on its own portnum

* Add to Ext. Notification and consolidate logic

* RANGE_TEST_APP portnum for RangeTestModule
2023-08-19 07:46:34 -05:00
github-actions[bot]
2dbdda204f [create-pull-request] automated change (#2731)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-08-18 10:17:55 -05:00
Jonathan Bennett
4767bd5497 Rename utils.h to avoid collision with library. (#2730) 2023-08-17 20:22:34 -05:00
Thomas Göttgens
05efd68097 Merge pull request #2729 from meshtastic/trunk-fmt
update trunk to latest version
2023-08-17 13:46:44 +02:00
Thomas Göttgens
a90eef432f update trunk to latest version 2023-08-17 12:17:36 +02:00
Thomas Göttgens
762166495f Merge branch 'master' into raspi-portduino 2023-08-17 10:06:34 +02:00
Ben Meadors
929b8f6209 Fix thread to use getConfiguredOrDefaultMs (#2727)
* WIP

* Updates

* Move it out of the macro guard so portduino can build

* Changes from feedback

* Use minimum_broadcast_secs as interval if we just broadcasted to avoid wasting cpu cycles

* Fmt

* Merge conflict resolution boogered me up

* Missed a spot

* getConfiguredOrDefaultMs

* Get the minimum interval
2023-08-16 15:08:06 -05:00
Thomas Göttgens
5d76771fab Permanently Enable Canned Messages on T-Deck and Picomputer (#2728)
* - Permanently Enable Canned Messages on T-Deck and Picomputer
- picomputer has a really dark TFT; switch color to white for better UX.

* well, you know... bullock...
2023-08-16 15:07:22 -05:00
Thomas Göttgens
91eb64d7b7 Fix warning about init order (#2725) 2023-08-15 20:17:15 -05:00
Ben Meadors
03fe4c629a Dection Sensor module duty cycle interval optimization (#2723)
* WIP

* Updates

* Move it out of the macro guard so portduino can build

* Changes from feedback

* Use minimum_broadcast_secs as interval if we just broadcasted to avoid wasting cpu cycles

* Fmt

* Merge conflict resolution boogered me up

* Missed a spot
2023-08-15 12:23:07 -05:00
Ben Meadors
144dfe9805 Initial Detection sensor module feature (#2722)
* WIP

* Updates

* Doh!

* Move it out of the macro guard so portduino can build

* Changes from feedback
2023-08-14 19:00:51 -05:00
rcarteraz
18899fd168 Update variant.h (#2719)
remove HAS_GPS 0 so users can add gps

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-08-13 23:45:23 -05:00
code8buster
fcfd83bc89 Remove auto GPS shutoff for fixed position nodes (#2720) 2023-08-13 15:56:49 -05:00
github-actions[bot]
a3d2b6166c [create-pull-request] automated change (#2716)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-08-12 20:49:42 -05:00
Ben Meadors
00ea6ef5ad Merge branch 'master' into raspi-portduino 2023-08-12 09:40:26 -05:00
Thomas Göttgens
b5b66f43f2 Merge branch 'master' into raspi-portduino 2023-08-09 11:19:23 +02:00
Thomas Göttgens
1e71d346ae Merge branch 'master' into raspi-portduino 2023-08-03 21:36:43 +02:00
Ben Meadors
919b2d1e48 Merge branch 'master' into raspi-portduino 2023-07-31 19:00:00 -05:00
Thomas Göttgens
171cca435e Merge branch 'master' into raspi-portduino 2023-07-24 11:00:58 +02:00
Thomas Göttgens
e878f55ed3 Merge branch 'master' into raspi-portduino 2023-06-27 18:13:24 +02:00
Thomas Göttgens
d74cbdaa8b update platform def 2023-05-23 21:55:12 +02:00
Ben Meadors
3a5b79e4c1 Merge branch 'master' into raspi-portduino 2023-05-23 07:51:32 -05:00
Ben Meadors
9bee35118f Merge branch 'master' into raspi-portduino 2023-05-18 06:47:56 -05:00
Thomas Göttgens
80f029aa32 Merge branch 'master' into raspi-portduino 2023-05-10 17:13:32 +02:00
Thomas Göttgens
b75aa79da5 Merge branch 'master' into raspi-portduino 2023-05-08 10:32:36 +02:00
Thomas Göttgens
49febc0d9d Merge branch 'master' into raspi-portduino 2023-04-24 14:58:20 +02:00
Thomas Göttgens
85818b8dfd Merge branch 'master' into raspi-portduino 2023-04-21 16:50:48 +02:00
Thomas Göttgens
7d299b06a7 Merge branch 'master' into raspi-portduino 2023-04-04 15:00:31 +02:00
Thomas Göttgens
14080d4667 Merge branch 'master' into raspi-portduino 2023-04-02 21:24:49 +02:00
Thomas Göttgens
8a806efb95 Merge branch 'master' into raspi-portduino 2023-03-27 15:30:05 +02:00
Thomas Göttgens
ef2d0cb830 Merge branch 'master' into raspi-portduino 2023-03-21 09:31:49 +01:00
Ben Meadors
5e779bfb33 Merge branch 'master' into raspi-portduino 2023-03-16 14:43:23 -05:00
Thomas Göttgens
498964e04e Merge branch 'master' into raspi-portduino 2023-03-04 17:24:37 +01:00
Thomas Göttgens
7d0bea267a Merge branch 'master' into raspi-portduino 2023-02-22 10:08:20 +01:00
Thomas Göttgens
ed1aa9ddb0 Merge branch 'master' into raspi-portduino 2023-02-17 12:34:00 +01:00
Thomas Göttgens
97a0b164be Merge branch 'master' into raspi-portduino 2023-02-10 00:21:47 +01:00
Ben Meadors
82706a961f Merge branch 'master' into raspi-portduino 2023-02-08 07:40:36 -06:00
Thomas Göttgens
06a1b079da even more cleanup-ing and revert-ing 2023-02-02 11:47:47 +01:00
Thomas Göttgens
56afed84df revert some more 2023-02-02 11:35:30 +01:00
Thomas Göttgens
945fd7a05c revert readprops change 2023-02-02 11:32:00 +01:00
Thomas Göttgens
e9a55fc296 revert them trunk shite 2023-02-02 11:29:55 +01:00
Thomas Göttgens
472c43aace Merge remote-tracking branch 'remotes/origin/master' into raspi-portduino 2023-02-02 10:49:45 +01:00
Thomas Göttgens
8b5937892b Merge pull request #2100 from meshtastic/develop
Update Raspi branch
2023-01-04 21:11:47 +01:00
Thomas Göttgens
8c20fe5ec4 Start working on RF95 attached to Raspberry Pi 2022-12-30 21:44:51 +01:00
217 changed files with 4981 additions and 2218 deletions

View File

@@ -7,7 +7,7 @@
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
- Please do not check in files that don't have real changes
- Please do not reformat lines that you didn't have to change the code on
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor along with the ['Trunk Check' extension](https://marketplace.visualstudio.com/items?itemName=trunk.io) (WSL2 is required on windows),
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor along with the ['Trunk Check' extension](https://marketplace.visualstudio.com/items?itemName=trunk.io) (In beta for windows, WSL2 for the linux version),
because it automatically follows our indentation rules and its auto reformatting will not cause spurious changes to lines.
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
- If your other co-developers have comments on your PR please tweak as needed.

45
.github/workflows/build_raspbian.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Build Raspbian
on: workflow_call
permissions:
contents: write
packages: write
jobs:
build-raspbian:
runs-on: [self-hosted, linux, ARM64]
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Upgrade python tools
shell: bash
run: |
python -m pip install --upgrade pip
pip install -U platformio adafruit-nrfutil
pip install -U meshtastic --pre
- name: Upgrade platformio
shell: bash
run: |
pio upgrade
- name: Build Raspbian
run: bin/build-native.sh
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-raspbian-${{ steps.version.outputs.version }}.zip
path: |
release/meshtasticd_linux_arm64
bin/config-dist.yaml

View File

@@ -103,7 +103,6 @@ jobs:
build-nrf52:
strategy:
fail-fast: false
max-parallel: 2
matrix:
include:
- board: rak4631
@@ -129,6 +128,15 @@ jobs:
with:
board: ${{ matrix.board }}
build-raspbian:
strategy:
fail-fast: false
max-parallel: 1
uses: ./.github/workflows/build_raspbian.yml
package-raspbian:
uses: ./.github/workflows/package_raspbian.yml
build-native:
runs-on: ubuntu-latest
steps:
@@ -204,7 +212,15 @@ jobs:
gather-artifacts:
runs-on: ubuntu-latest
needs:
[build-esp32, build-esp32-s3, build-nrf52, build-native, build-rpi2040]
[
build-esp32,
build-esp32-s3,
build-nrf52,
build-raspbian,
build-native,
build-rpi2040,
package-raspbian,
]
steps:
- name: Checkout code
uses: actions/checkout@v3
@@ -216,12 +232,15 @@ jobs:
with:
path: ./
- name: Display structure of downloaded files
run: ls -R
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Move files up
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_arm64 ./firmware-raspbian-*/bin/config-dist.yaml
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v3
@@ -233,6 +252,8 @@ jobs:
./firmware-*-ota.zip
./device-*.sh
./device-*.bat
./meshtasticd_linux_arm64
./config-dist.yaml
retention-days: 90
- uses: actions/download-artifact@v3
@@ -294,6 +315,13 @@ jobs:
name: firmware-${{ steps.version.outputs.version }}
path: ./output
- uses: actions/download-artifact@v3
with:
name: artifact-deb
- name: Display structure of downloaded files
run: ls -R
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh
@@ -347,6 +375,16 @@ jobs:
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip
- name: Add raspbian .deb
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
asset_name: meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
asset_content_type: application/vnd.debian.binary-package
- name: Bump version.properties
run: >-
bin/bump_version.py

60
.github/workflows/package_raspbian.yml vendored Normal file
View File

@@ -0,0 +1,60 @@
name: Package Raspbian
on: workflow_call
permissions:
contents: write
packages: write
jobs:
build-raspbian:
uses: ./.github/workflows/build_raspbian.yml
package-raspbian:
runs-on: ubuntu-latest
needs: build-raspbian
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: firmware-raspbian-${{ steps.version.outputs.version }}.zip
- name: Display structure of downloaded files
run: ls -R
- name: build .debpkg
run: |
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
mkdir -p .debpkg/usr/lib/systemd/system/
cp release/meshtasticd_linux_arm64 .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
- uses: jiro4989/build-deb-action@v3
with:
package: meshtasticd
package_root: .debpkg
maintainer: Jonathan Bennett
version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.*
arch: arm64
depends: libyaml-cpp0.7
desc: Native Linux Meshtastic binary.
- uses: actions/upload-artifact@v3
with:
name: artifact-deb
path: |
./*.deb

22
.github/workflows/trunk-check.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Pull Request
on: [pull_request]
concurrency:
group: ${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions: read-all
jobs:
trunk_check:
name: Trunk Check Runner
runs-on: ubuntu-latest
permissions:
checks: write # For trunk to post annotations
contents: read # For repo checkout
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Trunk Check
uses: trunk-io/trunk-action@v1

2
.trunk/.gitignore vendored
View File

@@ -2,7 +2,7 @@
*logs
*actions
*notifications
*tools
plugins
user_trunk.yaml
user.yaml
shims

View File

@@ -1,7 +1,10 @@
enable=all
source-path=SCRIPTDIR
disable=SC2154
disable=SC2248
disable=SC2250
# If you're having issues with shellcheck following source, disable the errors via:
# disable=SC1090
# disable=SC1091
#

View File

@@ -3,7 +3,7 @@ rules:
required: only-when-needed
extra-allowed: ["{|}"]
empty-values:
forbid-in-block-mappings: true
forbid-in-block-mappings: false
forbid-in-flow-mappings: true
key-duplicates: {}
octal-values:

View File

@@ -1,48 +1,44 @@
version: 0.1
cli:
version: 1.10.0
version: 1.17.1
plugins:
sources:
- id: trunk
ref: v0.0.17
ref: v1.2.6
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- taplo@0.7.0
- ruff@0.0.265
- bandit@1.7.5
- checkov@3.0.16
- terrascan@1.18.3
- trivy@0.46.1
- trufflehog@3.62.1
- taplo@0.8.1
- ruff@0.1.3
- yamllint@1.32.0
- isort@5.12.0
- markdownlint@0.34.0
- oxipng@8.0.0
- markdownlint@0.37.0
- oxipng@9.0.0
- svgo@3.0.2
- actionlint@1.6.24
- flake8@6.0.0
- actionlint@1.6.26
- flake8@6.1.0
- hadolint@2.12.0
- shfmt@3.5.0
- shfmt@3.6.0
- shellcheck@0.9.0
- black@23.3.0
- black@23.9.1
- git-diff-check
- gitleaks@8.16.3
- clang-format@14.0.0
- prettier@2.8.8
disabled:
- taplo@0.7.0
- shellcheck@0.9.0
- shfmt@3.5.0
- oxipng@8.0.0
- actionlint@1.6.22
- markdownlint@0.34.0
- hadolint@2.12.0
- svgo@3.0.2
- gitleaks@8.18.0
- clang-format@16.0.3
- prettier@3.0.3
runtimes:
enabled:
- python@3.10.8
- go@1.19.5
- go@1.21.0
- node@18.12.1
actions:
disabled:
- trunk-announce
- trunk-check-pre-push
- trunk-fmt-pre-commit
enabled:
- trunk-fmt-pre-commit
- trunk-check-pre-push
- trunk-upgrade-available

View File

@@ -10,8 +10,8 @@
This repository contains the device firmware for the Meshtastic project.
**[Building Instructions](https://meshtastic.org/docs/development/firmware/build)**
**[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)**
- **[Building Instructions](https://meshtastic.org/docs/development/firmware/build)**
- **[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)**
## Stats

View File

@@ -1,7 +1,7 @@
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
platform = platformio/espressif32@^6.3.2
platform = platformio/espressif32@6.3.2 # This is a temporary fix to the S3-based devices bluetooth issues until we can determine what within ESP-IDF changed and can develop a suitable patch.
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
@@ -38,7 +38,7 @@ lib_deps =
${networking_base.lib_deps}
${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0
h2zero/NimBLE-Arduino@^1.4.1
jgromes/RadioLib@^6.1.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
@@ -57,4 +57,4 @@ lib_ignore =
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv
board_build.partitions = partition-table.csv

View File

@@ -2,8 +2,8 @@
set -e
VERSION=`bin/buildinfo.py long`
SHORT_VERSION=`bin/buildinfo.py short`
VERSION=$(bin/buildinfo.py long)
SHORT_VERSION=$(bin/buildinfo.py short)
OUTDIR=release/
@@ -13,11 +13,15 @@ mkdir -p $OUTDIR/
rm -r $OUTDIR/* || true
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio pkg update
platformio pkg update
pio run --environment native
cp .pio/build/native/program $OUTDIR/meshtasticd_linux_amd64
if command -v raspi-config &>/dev/null; then
pio run --environment raspbian
cp .pio/build/raspbian/program $OUTDIR/meshtasticd_linux_arm64
else
pio run --environment native
cp .pio/build/native/program $OUTDIR/meshtasticd_linux_amd64
fi
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

21
bin/config-dist.yaml Normal file
View File

@@ -0,0 +1,21 @@
# Define your devices here using Broadcom pin numbering
# Uncomment the block that corresponds to your hardware
---
Lora:
# Module: sx1262 # Waveshare SX126X XXXM
# DIO2_AS_RF_SWITCH: true
# CS: 21
# IRQ: 16
# Busy: 20
# Reset: 18
# Module: sx1262 # Waveshare SX1302 LISTEN ONLY AT THIS TIME!
# CS: 7
# IRQ: 17
# Reset: 22
# Module: RF95 # Adafruit RFM9x
# Reset: 25
# CS: 7
# IRQ: 22
# Busy: 23

9
bin/meshtasticd.service Normal file
View File

@@ -0,0 +1,9 @@
[unit]
description=Meshtastic Native Daemon
[Service]
Type=simple
ExecStart=/usr/sbin/meshtasticd
[Install]
WantedBy=multi-user.target

10
bin/native-install.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
cp release/meshtasticd_linux_arm64 /usr/sbin/meshtasticd
mkdir /etc/meshtasticd
if [[ -f "/etc/meshtasticd/config.yaml" ]]; then
cp bin/config-dist.yaml /etc/meshtasticd/config-upgrade.yaml
else
cp bin/config-dist.yaml /etc/meshtasticd/config.yaml
fi
cp bin/meshtasticd.service /usr/lib/systemd/system/meshtasticd.service

View File

@@ -1,7 +1,8 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld"
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
@@ -13,7 +14,7 @@
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "t-deck"

View File

@@ -1,7 +1,8 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld"
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
@@ -14,7 +15,7 @@
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "t-watch-s3"
@@ -31,8 +32,9 @@
"maximum_size": 8388608,
"require_upload_port": true,
"use_1200bps_touch": true,
"wait_for_upload_port": true
"wait_for_upload_port": true,
"speed": 921600
},
"url": "http://www.lilygo.cn/",
"url": "https://www.lilygo.cc/en-pl/products/t-watch-s3",
"vendor": "LilyGo"
}

View File

@@ -15,7 +15,7 @@
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"hwids": [["0X303A", "0x1001"]],
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "tbeam-s3-core"
},

View File

@@ -26,6 +26,7 @@
;default_envs = meshtastic-dr-dev
;default_envs = m5stack-coreink
;default_envs = rak4631
;default_envs = rak10701
default_envs = wio-e5
extra_configs =
@@ -70,7 +71,7 @@ lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306
https://github.com/mathertel/OneButton#2.1.0 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
https://github.com/meshtastic/TinyGPSPlus.git#076e8d2c8fb702d9be5b08c55b93ff76f8af7e61
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1
@@ -113,6 +114,7 @@ lib_deps =
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
boschsensortec/BME68x Sensor Library@^1.1.40407
adafruit/Adafruit MCP9808 Library@^2.0.0
https://github.com/Tinyu-Zhao/INA3221@^0.0.1
adafruit/Adafruit INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0
adafruit/Adafruit SHTC3 Library@^1.0.0

View File

@@ -0,0 +1,75 @@
#include "configuration.h"
#ifdef HAS_NCP5623
#include <graphics/RAKled.h>
NCP5623 rgb;
#endif
namespace concurrency
{
class AmbientLightingThread : public concurrency::OSThread
{
public:
AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLightingThread")
{
// Uncomment to test module
// moduleConfig.ambient_lighting.led_state = true;
// moduleConfig.ambient_lighting.current = 10;
// // Default to a color based on our node number
// moduleConfig.ambient_lighting.red = (myNodeInfo.my_node_num & 0xFF0000) >> 16;
// moduleConfig.ambient_lighting.green = (myNodeInfo.my_node_num & 0x00FF00) >> 8;
// moduleConfig.ambient_lighting.blue = myNodeInfo.my_node_num & 0x0000FF;
#ifdef HAS_NCP5623
_type = type;
if (_type == ScanI2C::DeviceType::NONE) {
LOG_DEBUG("AmbientLightingThread disabling due to no RGB leds found on I2C bus\n");
disable();
return;
}
if (!moduleConfig.ambient_lighting.led_state) {
LOG_DEBUG("AmbientLightingThread disabling due to moduleConfig.ambient_lighting.led_state OFF\n");
disable();
return;
}
LOG_DEBUG("AmbientLightingThread initializing\n");
if (_type == ScanI2C::NCP5623) {
rgb.begin();
setLighting();
}
#endif
}
protected:
int32_t runOnce() override
{
#ifdef HAS_NCP5623
if (_type == ScanI2C::NCP5623 && moduleConfig.ambient_lighting.led_state) {
setLighting();
return 30000; // 30 seconds to reset from any animations that may have been running from Ext. Notification
} else {
return disable();
}
#else
return disable();
#endif
}
private:
ScanI2C::DeviceType _type = ScanI2C::DeviceType::NONE;
void setLighting()
{
#ifdef HAS_NCP5623
rgb.setCurrent(moduleConfig.ambient_lighting.current);
rgb.setRed(moduleConfig.ambient_lighting.red);
rgb.setGreen(moduleConfig.ambient_lighting.green);
rgb.setBlue(moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n",
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
moduleConfig.ambient_lighting.blue);
#endif
}
};
} // namespace concurrency

View File

@@ -164,15 +164,17 @@ class ButtonThread : public concurrency::OSThread
static void userButtonMultiPressed()
{
#if defined(GPS_POWER_TOGGLE)
if (config.position.gps_enabled) {
LOG_DEBUG("Flag set to false for gps power\n");
} else {
LOG_DEBUG("Flag set to true to restore power\n");
if (!config.device.disable_triple_click && (gps != nullptr)) {
config.position.gps_enabled = !(config.position.gps_enabled);
if (config.position.gps_enabled) {
LOG_DEBUG("Flag set to true to restore power\n");
gps->enable();
} else {
LOG_DEBUG("Flag set to false for gps power\n");
gps->disable();
}
}
config.position.gps_enabled = !(config.position.gps_enabled);
doGPSpowersave(config.position.gps_enabled);
#endif
}
static void userButtonPressedLongStart()

34
src/DisplayFormatters.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include "DisplayFormatters.h"
const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName)
{
switch (preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
return useShortName ? "ShortS" : "ShortSlow";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
return useShortName ? "ShortF" : "ShortFast";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
return useShortName ? "MedS" : "MediumSlow";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
return useShortName ? "MedF" : "MediumFast";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
return useShortName ? "LongS" : "LongSlow";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
return useShortName ? "LongF" : "LongFast";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
return useShortName ? "LongM" : "LongMod";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
return useShortName ? "VeryL" : "VLongSlow";
break;
default:
return useShortName ? "Custom" : "Invalid";
break;
}
}

8
src/DisplayFormatters.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include "NodeDB.h"
class DisplayFormatters
{
public:
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName);
};

View File

@@ -16,8 +16,8 @@
#include "buzz/buzz.h"
#include "configuration.h"
#include "main.h"
#include "meshUtils.h"
#include "sleep.h"
#include "utils.h"
#ifdef DEBUG_HEAP_MQTT
#include "mqtt/MQTT.h"
@@ -52,6 +52,7 @@ static const adc_atten_t atten = ADC_ATTENUATION;
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
INA260Sensor ina260Sensor;
INA219Sensor ina219Sensor;
INA3221Sensor ina3221Sensor;
#endif
#ifdef HAS_PMU
@@ -175,9 +176,21 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint32_t raw = 0;
#ifdef ARCH_ESP32
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
#ifdef ADC_CTRL
if (heltec_version == 5) {
pinMode(ADC_CTRL, OUTPUT);
digitalWrite(ADC_CTRL, HIGH);
delay(10);
}
#endif
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += adc1_get_raw(adc_channel);
}
#ifdef ADC_CTRL
if (heltec_version == 5) {
digitalWrite(ADC_CTRL, LOW);
}
#endif
#else // ADC2
int32_t adc_buf = 0;
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
@@ -221,10 +234,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
/**
* return true if there is a battery installed in this unit
*/
virtual bool isBatteryConnect() override
{
return getBatteryPercent() != -1;
}
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
@@ -245,10 +255,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
/// Assume charging if we have a battery and external power is connected.
/// we can't be smart enough to say 'full'?
virtual bool isCharging() override
{
return isBatteryConnect() && isVbusIn();
}
virtual bool isCharging() override { return isBatteryConnect() && isVbusIn(); }
private:
/// If we see a battery voltage higher than physics allows - assume charger is pumping
@@ -275,10 +282,14 @@ class AnalogBatteryLevel : public HasBatteryLevel
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO)
uint16_t getINAVoltage()
{
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) {
return ina219Sensor.getBusVoltageMv();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260].first ==
config.power.device_battery_ina_address) {
return ina260Sensor.getBusVoltageMv();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA3221].first ==
config.power.device_battery_ina_address) {
return ina3221Sensor.getBusVoltageMv();
}
return 0;
}
@@ -288,11 +299,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
if (!config.power.device_battery_ina_address) {
return false;
}
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) {
if (!ina219Sensor.isInitialized())
return ina219Sensor.runOnce() > 0;
return ina219Sensor.isRunning();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260].first ==
config.power.device_battery_ina_address) {
if (!ina260Sensor.isInitialized())
return ina260Sensor.runOnce() > 0;
return ina260Sensor.isRunning();
@@ -420,7 +432,7 @@ void Power::shutdown()
#ifdef PIN_LED3
ledOff(PIN_LED2);
#endif
doDeepSleep(DELAY_FOREVER);
doDeepSleep(DELAY_FOREVER, false);
#endif
}

View File

@@ -8,7 +8,6 @@
* actions to be taken upon entering or exiting each state.
*/
#include "PowerFSM.h"
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "configuration.h"
@@ -46,7 +45,7 @@ static void sdsEnter()
{
LOG_DEBUG("Enter state: SDS\n");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs));
doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs), false);
}
extern Power *power;
@@ -137,9 +136,6 @@ static void lsIdle()
static void lsExit()
{
LOG_INFO("Exit state: LS\n");
// setGPSPower(true); // restore GPS power
if (gps)
gps->forceWake(true);
}
static void nbEnter()
@@ -249,6 +245,8 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup()
{
bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0);
bool isTrackerOrSensor = config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR;
bool hasPower = isPowered();
LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0);
@@ -352,12 +350,12 @@ void PowerFSM_setup()
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
"Screen-on timeout");
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
#ifdef ARCH_ESP32
State *lowPowerState = &stateLS;
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
// See: https://github.com/meshtastic/firmware/issues/1071
if (isRouter || config.power.is_power_saving) {
// Don't add power saving transitions if we are a power saving tracker or sensor. Sleep will be initiatiated through the
// modules
if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) {
powerFSM.add_timed_transition(&stateNB, &stateLS,
getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL,
"Min wake timeout");
@@ -365,10 +363,6 @@ void PowerFSM_setup()
getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs),
NULL, "Bluetooth timeout");
}
if (config.power.sds_secs != UINT32_MAX)
powerFSM.add_timed_transition(lowPowerState, &stateSDS, getConfiguredOrDefaultMs(config.power.sds_secs), NULL,
"mesh timeout");
#endif
powerFSM.run_machine(); // run one iteration of the state machine, so we run our on enter tasks for the initial DARK state

View File

@@ -18,6 +18,12 @@ NoopPrint noopPrint;
#if HAS_WIFI || HAS_ETHERNET
extern Syslog syslog;
#endif
void RedirectablePrint::rpInit()
{
#ifdef HAS_FREE_RTOS
inDebugPrint = xSemaphoreCreateMutexStatic(&this->_MutexStorageSpace);
#endif
}
void RedirectablePrint::setDestination(Print *_dest)
{
@@ -66,9 +72,12 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
return 0;
}
size_t r = 0;
#ifdef HAS_FREE_RTOS
if (inDebugPrint != nullptr && xSemaphoreTake(inDebugPrint, portMAX_DELAY) == pdTRUE) {
#else
if (!inDebugPrint) {
inDebugPrint = true;
#endif
va_list arg;
va_start(arg, format);
@@ -141,7 +150,11 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
va_end(arg);
isContinuationMessage = !hasNewline;
#ifdef HAS_FREE_RTOS
xSemaphoreGive(inDebugPrint);
#else
inDebugPrint = false;
#endif
}
return r;

View File

@@ -1,5 +1,6 @@
#pragma once
#include "../freertosinc.h"
#include <Print.h>
#include <stdarg.h>
#include <string>
@@ -16,14 +17,19 @@ class RedirectablePrint : public Print
/// Used to allow multiple logDebug messages to appear on a single log line
bool isContinuationMessage = false;
#ifdef HAS_FREE_RTOS
SemaphoreHandle_t inDebugPrint = nullptr;
StaticSemaphore_t _MutexStorageSpace;
#else
volatile bool inDebugPrint = false;
#endif
public:
explicit RedirectablePrint(Print *_dest) : dest(_dest) {}
/**
* Set a new destination
*/
void rpInit();
void setDestination(Print *dest);
virtual size_t write(uint8_t c);
@@ -54,4 +60,4 @@ class NoopPrint : public Print
/**
* A printer that doesn't go anywhere
*/
extern NoopPrint noopPrint;
extern NoopPrint noopPrint;

View File

@@ -12,6 +12,7 @@ SerialConsole *console;
void consoleInit()
{
new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
DEBUG_PORT.rpInit(); // Simply sets up semaphore
}
void consolePrintf(const char *format, ...)

View File

@@ -53,7 +53,7 @@ class OSThread : public Thread
static void setup();
int32_t disable();
virtual int32_t disable();
/**
* Wait a specified number msecs starting from the current time (rather than the last time we were run)
@@ -67,6 +67,7 @@ class OSThread : public Thread
* Returns desired period for next invocation (or RUN_SAME for no change)
*/
virtual int32_t runOnce() = 0;
bool sleepOnNextExecution = false;
// Do not override this
virtual void run();
@@ -87,4 +88,4 @@ extern bool hasBeenSetup;
void assertIsSetup();
} // namespace concurrency
} // namespace concurrency

View File

@@ -57,8 +57,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define REQUIRE_RADIO true // If true, we will fail to start if the radio is not found
/// Convert a preprocessor name into a quoted string
#define xstr(s) str(s)
#define str(s) #s
#define xstr(s) ystr(s)
#define ystr(s) #s
/// Convert a preprocessor name into a quoted string and if that string is empty use "unset"
#define optstr(s) (xstr(s)[0] ? xstr(s) : "unset")
@@ -101,6 +101,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
#define CARDKB_ADDR 0x5F
#define TDECK_KB_ADDR 0x55
#define BBQ10_KB_ADDR 0x1F
// -----------------------------------------------------------------------------
// SENSOR
@@ -110,6 +111,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MCP9808_ADDR 0x18
#define INA_ADDR 0x40
#define INA_ADDR_ALTERNATE 0x41
#define INA3221_ADDR 0x42
#define QMC6310_ADDR 0x1C
#define QMI8658_ADDR 0x6B
#define QMC5883L_ADDR 0x1E
@@ -144,9 +146,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define GPS_BAUDRATE 9600
#ifndef GPS_THREAD_INTERVAL
#define GPS_THREAD_INTERVAL 100
#define GPS_THREAD_INTERVAL 200
#endif
// convert 24-bit color to 16-bit (56K)
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
/* Step #1: offer chance for variant-specific defines */
#include "variant.h"
@@ -183,6 +188,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef HAS_TELEMETRY
#define HAS_TELEMETRY 0
#endif
#ifndef HAS_SENSOR
#define HAS_SENSOR 0
#endif
#ifndef HAS_RADIO
#define HAS_RADIO 0
#endif

View File

@@ -30,8 +30,8 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, RAK14004};
return firstOfOrNONE(3, types);
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004};
return firstOfOrNONE(4, types);
}
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const

View File

@@ -17,6 +17,7 @@ class ScanI2C
RTC_PCF8563,
CARDKB,
TDECKKB,
BBQ10KB,
RAK14004,
PMU_AXP192_AXP2101,
BME_680,
@@ -24,6 +25,7 @@ class ScanI2C
BMP_280,
INA260,
INA219,
INA3221,
MCP9808,
SHT31,
SHTC3,

View File

@@ -213,6 +213,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
break;
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found\n");
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
#ifdef HAS_NCP5623
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
@@ -250,7 +251,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
type = INA219;
}
break;
case INA3221_ADDR:
LOG_INFO("INA3221 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = INA3221;
break;
case MCP9808_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
if (registerValue == 0x0400) {

View File

@@ -18,6 +18,8 @@ class ScanI2CTwoWire : public ScanI2C
ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override;
TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
bool exists(ScanI2C::DeviceType) const override;
size_t countDevices() const override;
@@ -51,6 +53,4 @@ class ScanI2CTwoWire : public ScanI2C
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const;
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
};

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,16 @@
#include "GPSStatus.h"
#include "Observer.h"
#include "TinyGPS++.h"
#include "concurrency/OSThread.h"
#include "input/RotaryEncoderInterruptImpl1.h"
#include "input/UpDownInterruptImpl1.h"
#include "modules/PositionModule.h"
// Allow defining the polarity of the ENABLE output. default is active high
#ifndef GPS_EN_ACTIVE
#define GPS_EN_ACTIVE 1
#endif
struct uBloxGnssModelInfo {
char swVersion[30];
@@ -18,6 +27,13 @@ typedef enum {
GNSS_MODEL_UNKNOWN,
} GnssModel_t;
typedef enum {
GNSS_RESPONSE_NONE,
GNSS_RESPONSE_NAK,
GNSS_RESPONSE_FRAME_ERRORS,
GNSS_RESPONSE_OK,
} GPS_RESPONSE;
// Generate a string representation of DOP
const char *getDOPString(uint32_t dop);
@@ -28,8 +44,29 @@ const char *getDOPString(uint32_t dop);
*/
class GPS : private concurrency::OSThread
{
TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA
uint32_t lastChecksumFailCount = 0;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
// via optional feature "custom fields", currently disabled (bug #525)
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
uint8_t fixType = 0; // fix type from GPGSA
#endif
private:
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastWhileActiveMsec = 0;
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0;
const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600};
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;
uint32_t en_gpio = 0;
int32_t averageLockTime = 0;
uint32_t GPSCycles = 0;
int speedSelect = 0;
int probeTries = 2;
/**
* hasValidLocation - indicates that the position variables contain a complete
@@ -39,15 +76,17 @@ class GPS : private concurrency::OSThread
bool isAwake = false; // true if we want a location right now
bool wakeAllowed = true; // false if gps must be forced to sleep regardless of what time it is
bool isInPowersave = false;
bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop()
bool hasGPS = false; // Do we have a GPS we are talking to
bool GPSInitFinished = false; // Init thread finished?
bool GPSInitStarted = false; // Init thread finished?
uint8_t numSatellites = 0;
CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep);
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
CallbackObserver<GPS, void *> notifyGPSSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
@@ -55,6 +94,24 @@ class GPS : private concurrency::OSThread
/** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps;
static uint8_t _message_PMREQ[];
static const uint8_t _message_CFG_RXM_PSM[];
static const uint8_t _message_CFG_RXM_ECO[];
static const uint8_t _message_CFG_PM2[];
static const uint8_t _message_GNSS_7[];
static const uint8_t _message_GNSS[];
static const uint8_t _message_JAM[];
static const uint8_t _message_NAVX5[];
static const uint8_t _message_1HZ[];
static const uint8_t _message_GGL[];
static const uint8_t _message_GSA[];
static const uint8_t _message_GSV[];
static const uint8_t _message_VTG[];
static const uint8_t _message_RMC[];
static const uint8_t _message_GGA[];
static const uint8_t _message_PMS[];
static const uint8_t _message_SAVE[];
meshtastic_Position p = meshtastic_Position_init_default;
GPS() : concurrency::OSThread("GPS") {}
@@ -69,6 +126,14 @@ class GPS : private concurrency::OSThread
*/
virtual bool setup();
// re-enable the thread
void enable();
// Disable the thread
int32_t disable() override;
void setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime);
/// Returns true if we have acquired GPS lock.
virtual bool hasLock();
@@ -80,71 +145,20 @@ class GPS : private concurrency::OSThread
bool isPowerSaving() const { return !config.position.gps_enabled; }
/**
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP
* called after the CPU wakes from light-sleep state
*
* Or set to false, to disallow any sort of waking
* */
void forceWake(bool on);
// Some GPS modules (ublock) require factory reset
virtual bool factoryReset() { return true; }
// Empty the input buffer as quickly as possible
void clearBuffer();
protected:
/// Do gps chipset specific init, return true for success
virtual bool setupGPS();
// 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);
/// If possible force the GPS into sleep/low power mode
virtual void sleep();
// scratch space for creating ublox packets
uint8_t UBXscratch[250] = {0};
/// wake the GPS into normal operation mode
virtual void wake();
int rebootsSeen = 0;
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle() = 0;
/** Idle processing while GPS is looking for lock, called once per secondish */
virtual void 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() = 0;
/**
* 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() = 0;
/// Record that we have a GPS
void setConnected();
void setNumSatellites(uint8_t n);
private:
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareSleep(void *unused);
/// 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);
// Calculate checksum
void UBXChecksum(byte *message, size_t length);
int getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID, uint32_t waitMillis);
GPS_RESPONSE getACK(uint8_t c, uint8_t i, uint32_t waitMillis);
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
/**
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
@@ -152,6 +166,59 @@ class GPS : private concurrency::OSThread
* calls sleep/wake
*/
void setAwake(bool on);
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();
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 whileIdle();
/**
* 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);
// Calculate checksum
void UBXChecksum(uint8_t *message, size_t length);
/** Get how long we should stay looking for each aquisition
*/
@@ -161,8 +228,6 @@ class GPS : private concurrency::OSThread
*/
uint32_t getSleepTime() const;
bool getACK(uint8_t c, uint8_t i);
/**
* Tell users we have new GPS readings
*/
@@ -172,9 +237,7 @@ class GPS : private concurrency::OSThread
// Get GNSS model
String getNMEA();
GnssModel_t probe();
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
GnssModel_t probe(int serialSpeed);
// delay counter to allow more sats before fixed position stops GPS thread
uint8_t fixeddelayCtr = 0;
@@ -183,8 +246,4 @@ class GPS : private concurrency::OSThread
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
};
// Creates an instance of the GPS class.
// Returns the new instance or null if the GPS is not present.
GPS *createGps();
extern GPS *gps;

View File

@@ -1,272 +0,0 @@
#include "NMEAGPS.h"
#include "RTC.h"
#include "configuration.h"
#include <TinyGPS++.h>
// GPS solutions older than this will be rejected - see TinyGPSDatum::age()
#define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway
#define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc)
static int32_t toDegInt(RawDegrees d)
{
int32_t degMult = 10000000; // 1e7
int32_t r = d.deg * degMult + d.billionths / 100;
if (d.negative)
r *= -1;
return r;
}
bool NMEAGPS::factoryReset()
{
#ifdef PIN_GPS_REINIT
// The L76K GNSS on the T-Echo requires the RESET pin to be pulled LOW
digitalWrite(PIN_GPS_REINIT, 0);
pinMode(PIN_GPS_REINIT, OUTPUT);
delay(150); // The L76K datasheet calls for at least 100MS delay
digitalWrite(PIN_GPS_REINIT, 1);
#endif
// 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));
delay(1000);
return true;
}
bool NMEAGPS::setupGPS()
{
GPS::setupGPS();
#ifdef PIN_GPS_PPS
// pulse per second
// FIXME - move into shared GPS code
pinMode(PIN_GPS_PPS, INPUT);
#endif
// Currently disabled per issue #525 (TinyGPS++ crash bug)
// when fixed upstream, can be un-disabled to enable 3D FixType and PDOP
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// 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\n");
#else
LOG_DEBUG("GxGSA NOT available\n");
#endif
return true;
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool NMEAGPS::lookForTime()
{
auto ti = reader.time;
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).
*/
struct tm t;
t.tm_sec = ti.second();
t.tm_min = ti.minute();
t.tm_hour = ti.hour();
t.tm_mday = d.day();
t.tm_mon = d.month() - 1;
t.tm_year = d.year() - 1900;
t.tm_isdst = false;
if (t.tm_mon > -1) {
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t);
return true;
} else
return false;
} else
return false;
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool NMEAGPS::lookForLocation()
{
// By default, TinyGPS++ does not parse GPGSA lines, which give us
// the 2D/3D fixType (see NMEAGPS.h)
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
fixQual = reader.fixQuality();
#ifndef TINYGPS_OPTION_NO_STATISTICS
if (reader.failedChecksum() > lastChecksumFailCount) {
LOG_WARN("Warning, %u new GPS checksum failures, for a total of %u.\n", reader.failedChecksum() - lastChecksumFailCount,
reader.failedChecksum());
lastChecksumFailCount = reader.failedChecksum();
}
#endif
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
fixType = atoi(gsafixtype.value()); // will set to zero if no data
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
#endif
// check if GPS has an acceptable lock
if (!hasLock())
return false;
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n", reader.location.age(),
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
gsafixtype.age(),
#else
0,
#endif
reader.date.age(), reader.time.age());
#endif // GPS_EXTRAVERBOSE
// check if a complete GPS solution set is available for reading
// tinyGPSDatum::age() also includes isValid() test
// FIXME
if (!((reader.location.age() < GPS_SOL_EXPIRY_MS) &&
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
(gsafixtype.age() < GPS_SOL_EXPIRY_MS) &&
#endif
(reader.time.age() < GPS_SOL_EXPIRY_MS) && (reader.date.age() < GPS_SOL_EXPIRY_MS))) {
LOG_WARN("SOME data is TOO OLD: LOC %u, TIME %u, DATE %u\n", reader.location.age(), reader.time.age(), reader.date.age());
return false;
}
// Is this a new point or are we re-reading the previous one?
if (!reader.location.isUpdated())
return false;
// We know the solution is fresh and valid, so just read the data
auto loc = reader.location.value();
// Bail out EARLY to avoid overwriting previous good data (like #857)
if (toDegInt(loc.lat) > 900000000) {
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("Bail out EARLY on LAT %i\n", toDegInt(loc.lat));
#endif
return false;
}
if (toDegInt(loc.lng) > 1800000000) {
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("Bail out EARLY on LNG %i\n", toDegInt(loc.lng));
#endif
return false;
}
p.location_source = meshtastic_Position_LocSource_LOC_INTERNAL;
// Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
p.HDOP = reader.hdop.value();
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
// LOG_DEBUG("PDOP=%d, HDOP=%d\n", p.PDOP, p.HDOP);
#else
// FIXME! naive PDOP emulation (assumes VDOP==HDOP)
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)
p.HDOP = reader.hdop.value();
p.PDOP = 1.41 * reader.hdop.value();
#endif
// Discard incomplete or erroneous readings
if (reader.hdop.value() == 0) {
LOG_WARN("BOGUS hdop.value() REJECTED: %d\n", reader.hdop.value());
return false;
}
p.latitude_i = toDegInt(loc.lat);
p.longitude_i = toDegInt(loc.lng);
p.altitude_geoidal_separation = reader.geoidHeight.meters();
p.altitude_hae = reader.altitude.meters() + p.altitude_geoidal_separation;
p.altitude = reader.altitude.meters();
p.fix_quality = fixQual;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
p.fix_type = fixType;
#endif
// positional timestamp
struct tm t;
t.tm_sec = reader.time.second();
t.tm_min = reader.time.minute();
t.tm_hour = reader.time.hour();
t.tm_mday = reader.date.day();
t.tm_mon = reader.date.month() - 1;
t.tm_year = reader.date.year() - 1900;
t.tm_isdst = false;
p.timestamp = mktime(&t);
// Nice to have, if available
if (reader.satellites.isUpdated()) {
p.sats_in_view = reader.satellites.value();
}
if (reader.course.isUpdated() && reader.course.isValid()) {
if (reader.course.value() < 36000) { // sanity check
p.ground_track =
reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
} else {
LOG_WARN("BOGUS course.value() REJECTED: %d\n", reader.course.value());
}
}
if (reader.speed.isUpdated() && reader.speed.isValid()) {
p.ground_speed = reader.speed.kmph();
}
return true;
}
bool NMEAGPS::hasLock()
{
// Using GPGGA fix quality indicator
if (fixQual >= 1 && fixQual <= 5) {
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// Use GPGSA fix type 2D/3D (better) if available
if (fixType == 3 || fixType == 0) // zero means "no data received"
#endif
return true;
}
return false;
}
bool NMEAGPS::hasFlow()
{
return reader.passedChecksum() > 0;
}
bool NMEAGPS::whileIdle()
{
bool isValid = 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.\n", _serial_gps->available());
clearBuffer();
}
#endif
// if (_serial_gps->available() > 0)
// LOG_DEBUG("GPS Bytes Waiting: %u\n", _serial_gps->available());
// First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) {
int c = _serial_gps->read();
// LOG_DEBUG("%c", c);
isValid |= reader.encode(c);
}
return isValid;
}

View File

@@ -1,57 +0,0 @@
#pragma once
#include "GPS.h"
#include "Observer.h"
#include "TinyGPS++.h"
/**
* A gps class thatreads from a NMEA GPS stream (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class NMEAGPS : public GPS
{
TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA
uint32_t lastChecksumFailCount = 0;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
// via optional feature "custom fields", currently disabled (bug #525)
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
uint8_t fixType = 0; // fix type from GPGSA
#endif
public:
virtual bool setupGPS() override;
virtual bool factoryReset() override;
protected:
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation() override;
virtual bool hasLock() override;
virtual bool hasFlow() override;
};

View File

@@ -103,9 +103,8 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
bool shouldSet;
if (q > currentQuality) {
currentQuality = q;
shouldSet = true;
LOG_DEBUG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q);
LOG_DEBUG("Upgrading time to quality %d\n", q);
} else if (q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
shouldSet = true;
@@ -114,12 +113,12 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
shouldSet = false;
if (shouldSet) {
currentQuality = q;
lastSetMsec = now;
// This delta value works on all platforms
timeStartMsec = now;
zeroOffsetSecs = tv->tv_sec;
// If this platform has a setable RTC, set it
#ifdef RV3028_RTC
if (rtc_found.address == RV3028_RTC) {
@@ -209,4 +208,4 @@ uint32_t getTime()
uint32_t getValidTime(RTCQuality minQuality)
{
return (currentQuality >= minQuality) ? getTime() : 0;
}
}

192
src/gps/ubx.h Normal file
View File

@@ -0,0 +1,192 @@
uint8_t GPS::_message_PMREQ[] PROGMEM = {
0x00, 0x00, // 4 bytes duration of request task
0x00, 0x00, // (milliseconds)
0x02, 0x00, // Task flag bitfield
0x00, 0x00 // byte index 1 = sleep mode
};
const uint8_t GPS::_message_CFG_RXM_PSM[] PROGMEM = {
0x08, // Reserved
0x01 // Power save mode
};
const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = {
0x08, // Reserved
0x04 // eco mode
};
const uint8_t GPS::_message_CFG_PM2[] PROGMEM = {
0x01, 0x06, 0x00, 0x00, // version, Reserved
0x0E, 0x81, 0x43, 0x01, // flags
0xE8, 0x03, 0x00, 0x00, // update period 1000 ms
0x10, 0x27, 0x00, 0x00, // search period 10s
0x00, 0x00, 0x00, 0x00, // Grod offset 0
0x01, 0x00, // onTime 1 second
0x00, 0x00, // min search time 0
0x2C, 0x01, // reserved
0x00, 0x00, 0x4F, 0xC1, // reserved
0x03, 0x00, 0x87, 0x02, // reserved
0x00, 0x00, 0xFF, 0x00, // reserved
0x01, 0x00, 0xD6, 0x4D // reserved
};
const uint8_t GPS::_message_GNSS_7[] = {
0x00, // msgVer (0 for this version)
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
0x02, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x00, 0x01, // GPS
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x01 // SBAS
};
// It's not critical if the module doesn't acknowledge this configuration.
// The module should operate adequately with its factory or previously saved settings.
// It appears that there is a firmware bug in some GPS modules: When an attempt is made
// to overwrite a saved state with identical values, no ACK/NAK is received, contrary to
// what is specified in the Ublox documentation.
// There is also a possibility that the module may be GPS-only.
const uint8_t GPS::_message_GNSS[] = {
0x00, // msgVer (0 for this version)
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
0x03, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, // GPS
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, // SBAS
0x06, 0x08, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x01 // GLONASS
};
// Enable interference resistance, because we are using LoRa, WiFi and Bluetooth on same board,
// and we need to reduce interference from them
const uint8_t GPS::_message_JAM[] = {
// bbThreshold (Broadband jamming detection threshold) is set to 0x3F (63 in decimal)
// cwThreshold (CW jamming detection threshold) is set to 0x10 (16 in decimal)
// algorithmBits (Reserved algorithm settings) is set to 0x16B156 as recommended
// enable (Enable interference detection) is set to 1 (enabled)
0x3F, 0x10, 0xB1, 0x56, // config: Interference config word
// generalBits (General settings) is set to 0x31E as recommended
// antSetting (Antenna setting, 0=unknown, 1=passive, 2=active) is set to 0 (unknown)
// ToDo: Set to 1 (passive) or 2 (active) if known, for example from UBX-MON-HW, or from board info
// enable2 (Set to 1 to scan auxiliary bands, u-blox 8 / u-blox M8 only, otherwise ignored) is set to 1
// (enabled)
0x1E, 0x03, 0x00, 0x01 // config2: Extra settings for jamming/interference monitor
};
// Configure navigation engine expert settings:
const uint8_t GPS::_message_NAVX5[] = {
0x00, 0x00, // msgVer (0 for this version)
// minMax flag = 1: apply min/max SVs settings
// minCno flag = 1: apply minimum C/N0 setting
// initial3dfix flag = 0: apply initial 3D fix settings
// aop flag = 1: apply aopCfg (useAOP flag) settings (AssistNow Autonomous)
0x1B, 0x00, // mask1 (First parameters bitmask)
// adr flag = 0: apply ADR sensor fusion on/off setting (useAdr flag)
// If firmware is not ADR/UDR, enabling this flag will fail configuration
// ToDo: check this with UBX-MON-VER
0x00, 0x00, 0x00, 0x00, // mask2 (Second parameters bitmask)
0x00, 0x00, // Reserved
0x03, // minSVs (Minimum number of satellites for navigation) = 3
0x10, // maxSVs (Maximum number of satellites for navigation) = 16
0x06, // minCNO (Minimum satellite signal level for navigation) = 6 dBHz
0x00, // Reserved
0x00, // iniFix3D (Initial fix must be 3D) = 0 (disabled)
0x00, 0x00, // Reserved
0x00, // ackAiding (Issue acknowledgements for assistance message input) = 0 (disabled)
0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved
0x00, // Reserved
0x01, // aopCfg (AssistNow Autonomous configuration) = 1 (enabled)
0x00, 0x00, // Reserved
0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00, // Reserved
0x00, 0x00, 0x00, // Reserved
0x01, // useAdr (Enable/disable ADR sensor fusion) = 1 (enabled)
};
// Set GPS update rate to 1Hz
// Lowering the update rate helps to save power.
// Additionally, for some new modules like the M9/M10, an update rate lower than 5Hz
// is recommended to avoid a known issue with satellites disappearing.
const uint8_t GPS::_message_1HZ[] = {
0xE8, 0x03, // Measurement Rate (1000ms for 1Hz)
0x01, 0x00, // Navigation rate, always 1 in GPS mode
0x01, 0x00, // Time reference
};
// Disable GGL. GGL - Geographic position (latitude and longitude), which provides the current geographical
// coordinates.
const uint8_t GPS::_message_GGL[] = {
0xF0, 0x01, // NMEA ID for GLL
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x00, // Disable
0x01, 0x01, 0x01, 0x01 // Reserved
};
// Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
// the DOP (Dilution of Precision)
const uint8_t GPS::_message_GSA[] = {
0xF0, 0x02, // NMEA ID for GSA
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x01, // Enable
0x01, 0x01, 0x01, 0x01 // Reserved
};
// Disable GSV. GSV - Satellites in view, details the number and location of satellites in view.
const uint8_t GPS::_message_GSV[] = {
0xF0, 0x03, // NMEA ID for GSV
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x00, // Disable
0x01, 0x01, 0x01, 0x01 // Reserved
};
// Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to
// the ground.
const uint8_t GPS::_message_VTG[] = {
0xF0, 0x05, // NMEA ID for VTG
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x00, // Disable
0x01, 0x01, 0x01, 0x01 // Reserved
};
// Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data.
const uint8_t GPS::_message_RMC[] = {
0xF0, 0x04, // NMEA ID for RMC
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x01, // Enable
0x01, 0x01, 0x01, 0x01 // Reserved
};
// Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data.
const uint8_t GPS::_message_GGA[] = {
0xF0, 0x00, // NMEA ID for GGA
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x01, // Enable
0x01, 0x01, 0x01, 0x01 // Reserved
};
// The Power Management configuration allows the GPS module to operate in different power modes for optimized
// power consumption. The modes supported are: 0x00 = Full power: The module operates at full power with no power
// saving. 0x01 = Balanced: The module dynamically adjusts the tracking behavior to balance power consumption.
// 0x02 = Interval: The module operates in a periodic mode, cycling between tracking and power saving states.
// 0x03 = Aggressive with 1 Hz: The module operates in a power saving mode with a 1 Hz update rate.
// 0x04 = Aggressive with 2 Hz: The module operates in a power saving mode with a 2 Hz update rate.
// 0x05 = Aggressive with 4 Hz: The module operates in a power saving mode with a 4 Hz update rate.
// The 'period' field specifies the position update and search period. It is only valid when the powerSetupValue
// is set to Interval; otherwise, it must be set to '0'. The 'onTime' field specifies the duration of the ON phase
// and must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise,
// it must be set to '0'.
const uint8_t GPS::_message_PMS[] = {
0x00, // Version (0)
0x03, // Power setup value
0x00, 0x00, // period: not applicable, set to 0
0x00, 0x00, // onTime: not applicable, set to 0
0x97, 0x6F // reserved, generated by u-center
};
const uint8_t GPS::_message_SAVE[] = {
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x0F // deviceMask: BBR, Flash, EEPROM, and SPI Flash
};

View File

@@ -1,5 +1,3 @@
#include "main.h"
#ifdef HAS_NCP5623
#include <NCP5623.h>
extern NCP5623 rgb;

View File

@@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#if HAS_SCREEN
#include <OLEDDisplay.h>
#include "DisplayFormatters.h"
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
@@ -36,11 +37,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "mesh-pb-constants.h"
#include "mesh/Channels.h"
#include "mesh/generated/meshtastic/deviceonly.pb.h"
#include "meshUtils.h"
#include "modules/ExternalNotificationModule.h"
#include "modules/TextMessageModule.h"
#include "sleep.h"
#include "target_specific.h"
#include "utils.h"
#ifdef ARCH_ESP32
#include "esp_task_wdt.h"
@@ -160,17 +161,9 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl
xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
screen->forceDisplay();
// FIXME - draw serial # somewhere?
}
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// Draw region in upper left
const char *region = myRegion ? myRegion->name : NULL;
drawIconScreen(region, display, state, x, y);
}
static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// draw an xbm image.
@@ -220,6 +213,28 @@ static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
drawOEMIconScreen(region, display, state, x, y);
}
static void drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message)
{
uint16_t x_offset = display->width() / 2;
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(x_offset + x, 26 + y, message);
}
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
#ifdef ARCH_ESP32
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) {
drawFrameText(display, state, x, y, "Resuming...");
} else
#endif
{
// Draw region in upper left
const char *region = myRegion ? myRegion->name : NULL;
drawIconScreen(region, display, state, x, y);
}
}
// Used on boot when a certificate is being created
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
@@ -320,22 +335,6 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
display->drawString(x_offset + x, y_offset + y, deviceName);
}
static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
uint16_t x_offset = display->width() / 2;
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(x_offset + x, 26 + y, "Shutting down...");
}
static void drawFrameReboot(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
uint16_t x_offset = display->width() / 2;
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(x_offset + x, 26 + y, "Rebooting...");
}
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
@@ -365,7 +364,7 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
{
return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled;
return packet->from != 0 && !moduleConfig.store_forward.enabled;
}
/// Draw the last text message we received
@@ -906,20 +905,6 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
drawColumns(display, x, y, fields);
}
// #ifdef RAK4630
// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl),
// dispdev_oled(address, sda, scl), ui(&dispdev)
// {
// address_found = address;
// cmdQueue.setReader(this);
// if (screen_found) {
// (void)dispdev;
// AutoOLEDWire dispdev = dispdev_oled;
// (void)ui;
// OLEDDisplayUi ui(&dispdev);
// }
// }
// #else
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32),
dispdev(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE),
@@ -927,7 +912,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
{
cmdQueue.setReader(this);
}
// #endif
/**
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
@@ -1244,11 +1229,8 @@ void Screen::setWelcomeFrames()
{
if (address_found.address) {
// LOG_DEBUG("showing Welcome frames\n");
ui.disableAllIndicators();
static FrameCallback welcomeFrames[] = {drawWelcomeScreen};
ui.setFrames(welcomeFrames, 1);
ui.update();
static FrameCallback frames[] = {drawWelcomeScreen};
setFrameImmediateDraw(frames);
}
}
@@ -1335,12 +1317,15 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
LOG_DEBUG("showing bluetooth screen\n");
showingNormalScreen = false;
static FrameCallback btFrames[] = {drawFrameBluetooth};
static FrameCallback frames[] = {drawFrameBluetooth};
snprintf(btPIN, sizeof(btPIN), "%06u", pin);
setFrameImmediateDraw(frames);
}
void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
{
ui.disableAllIndicators();
ui.setFrames(btFrames, 1);
ui.setFrames(drawFrames, 1);
setFastFramerate();
}
@@ -1349,11 +1334,12 @@ void Screen::handleShutdownScreen()
LOG_DEBUG("showing shutdown screen\n");
showingNormalScreen = false;
static FrameCallback shutdownFrames[] = {drawFrameShutdown};
auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
drawFrameText(display, state, x, y, "Shutting down...");
};
static FrameCallback frames[] = {frame};
ui.disableAllIndicators();
ui.setFrames(shutdownFrames, 1);
setFastFramerate();
setFrameImmediateDraw(frames);
}
void Screen::handleRebootScreen()
@@ -1361,11 +1347,11 @@ void Screen::handleRebootScreen()
LOG_DEBUG("showing reboot screen\n");
showingNormalScreen = false;
static FrameCallback rebootFrames[] = {drawFrameReboot};
ui.disableAllIndicators();
ui.setFrames(rebootFrames, 1);
setFastFramerate();
auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
drawFrameText(display, state, x, y, "Rebooting...");
};
static FrameCallback frames[] = {frame};
setFrameImmediateDraw(frames);
}
void Screen::handleStartFirmwareUpdateScreen()
@@ -1373,11 +1359,8 @@ void Screen::handleStartFirmwareUpdateScreen()
LOG_DEBUG("showing firmware screen\n");
showingNormalScreen = false;
static FrameCallback btFrames[] = {drawFrameFirmware};
ui.disableAllIndicators();
ui.setFrames(btFrames, 1);
setFastFramerate();
static FrameCallback frames[] = {drawFrameFirmware};
setFrameImmediateDraw(frames);
}
void Screen::blink()
@@ -1638,65 +1621,8 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
} else {
// Codes:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
if (getWifiDisconnectReason() == 2) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Authentication Invalid");
} else if (getWifiDisconnectReason() == 3) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "De-authenticated");
} else if (getWifiDisconnectReason() == 4) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated Expired");
} else if (getWifiDisconnectReason() == 5) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP - Too Many Clients");
} else if (getWifiDisconnectReason() == 6) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_AUTHED");
} else if (getWifiDisconnectReason() == 7) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_ASSOCED");
} else if (getWifiDisconnectReason() == 8) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated");
} else if (getWifiDisconnectReason() == 9) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_NOT_AUTHED");
} else if (getWifiDisconnectReason() == 10) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_PWRCAP_BAD");
} else if (getWifiDisconnectReason() == 11) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_SUPCHAN_BAD");
} else if (getWifiDisconnectReason() == 13) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_INVALID");
} else if (getWifiDisconnectReason() == 14) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "MIC_FAILURE");
} else if (getWifiDisconnectReason() == 15) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Handshake Timeout");
} else if (getWifiDisconnectReason() == 16) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "GROUP_KEY_UPDATE_TIMEOUT");
} else if (getWifiDisconnectReason() == 17) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_IN_4WAY_DIFFERS");
} else if (getWifiDisconnectReason() == 18) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Group Cipher");
} else if (getWifiDisconnectReason() == 19) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Pairwise Cipher");
} else if (getWifiDisconnectReason() == 20) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AKMP_INVALID");
} else if (getWifiDisconnectReason() == 21) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "UNSUPP_RSN_IE_VERSION");
} else if (getWifiDisconnectReason() == 22) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "INVALID_RSN_IE_CAP");
} else if (getWifiDisconnectReason() == 23) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "802_1X_AUTH_FAILED");
} else if (getWifiDisconnectReason() == 24) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "CIPHER_SUITE_REJECTED");
} else if (getWifiDisconnectReason() == 200) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "BEACON_TIMEOUT");
} else if (getWifiDisconnectReason() == 201) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Not Found");
} else if (getWifiDisconnectReason() == 202) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AUTH_FAIL");
} else if (getWifiDisconnectReason() == 203) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_FAIL");
} else if (getWifiDisconnectReason() == 204) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "HANDSHAKE_TIMEOUT");
} else if (getWifiDisconnectReason() == 205) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
} else {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Unknown Status");
}
display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
WiFi.disconnectReasonName(static_cast<wifi_err_reason_t>(getWifiDisconnectReason())));
}
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
@@ -1743,37 +1669,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
display->drawString(x + 1, y, String("USB"));
}
auto mode = "";
switch (config.lora.modem_preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
mode = "ShortS";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
mode = "ShortF";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
mode = "MedS";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
mode = "MedF";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
mode = "LongS";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
mode = "LongF";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
mode = "LongM";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
mode = "VeryL";
break;
default:
mode = "Custom";
break;
}
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
if (config.display.heading_bold)
@@ -1840,23 +1736,6 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
heartbeat = !heartbeat;
#endif
}
// adjust Brightness cycle through 1 to 254 as long as attachDuringLongPress is true
void Screen::adjustBrightness()
{
if (!useDisplay)
return;
if (brightness == 254) {
brightness = 0;
} else {
brightness++;
}
int width = brightness / (254.00 / SCREEN_WIDTH);
dispdev.drawRect(0, 30, SCREEN_WIDTH, 4);
dispdev.fillRect(0, 31, width, 2);
dispdev.display();
dispdev.setBrightness(brightness);
}
int Screen::handleStatusUpdate(const meshtastic::Status *arg)
{

View File

@@ -19,7 +19,6 @@ class Screen
void setup() {}
void setOn(bool) {}
void print(const char *) {}
void adjustBrightness() {}
void doDeepSleep() {}
void forceDisplay() {}
void startBluetoothPinScreen(uint32_t pin) {}
@@ -161,7 +160,6 @@ class Screen : public concurrency::OSThread
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
// Implementation to Adjust Brightness
void adjustBrightness();
uint8_t brightness = BRIGHTNESS_DEFAULT;
/// Starts showing the Bluetooth PIN screen.
@@ -363,6 +361,9 @@ class Screen : public concurrency::OSThread
/// Try to start drawing ASAP
void setFastFramerate();
// Sets frame up for immediate drawing
void setFrameImmediateDraw(FrameCallback *drawFrames);
/// Called when debug screen is to be drawn, calls through to debugInfo.drawFrame.
static void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
@@ -389,7 +390,7 @@ class Screen : public concurrency::OSThread
SH1106Wire dispdev;
#elif defined(USE_SSD1306)
SSD1306Wire dispdev;
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014)
TFTDisplay dispdev;
#elif defined(USE_EINK)
EInkDisplay dispdev;

View File

@@ -1,12 +1,13 @@
#include "configuration.h"
#include "main.h"
#ifndef TFT_BACKLIGHT_ON
#define TFT_BACKLIGHT_ON HIGH
#endif
// convert 24-bit color to 16-bit (56K)
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
#ifndef TFT_MESH
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
#endif
#if defined(ST7735S)
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
@@ -81,8 +82,16 @@ class LGFX : public lgfx::LGFX_Device
{
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
#ifdef ST7735_BL_V03
if (heltec_version == 3) {
cfg.pin_bl = ST7735_BL_V03;
} else {
cfg.pin_bl = ST7735_BL_V05;
}
#else
cfg.pin_bl = ST7735_BL; // Pin number to which the backlight is connected
cfg.invert = true; // true to invert the brightness of the backlight
#endif
cfg.invert = true; // true to invert the brightness of the backlight
// cfg.freq = 44100; // PWM frequency of backlight
// cfg.pwm_channel = 1; // PWM channel number to use
@@ -96,6 +105,10 @@ class LGFX : public lgfx::LGFX_Device
static LGFX tft;
#elif defined(RAK14014)
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
#elif defined(ST7789_CS)
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
@@ -318,7 +331,7 @@ static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.
#endif
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER)
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014)
#include "SPILock.h"
#include "TFTDisplay.h"
#include <SPI.h>
@@ -364,25 +377,56 @@ void TFTDisplay::sendCommand(uint8_t com)
// handle display on/off directly
switch (com) {
case DISPLAYON: {
#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
if (heltec_version == 3) {
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
} else {
digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON);
}
#endif
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
#endif
#ifdef VTFT_CTRL_V03
if (heltec_version == 3) {
digitalWrite(VTFT_CTRL_V03, LOW);
} else {
digitalWrite(VTFT_CTRL_V05, LOW);
}
#endif
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, LOW);
#endif
#ifndef M5STACK
#ifdef RAK14014
#elif !defined(M5STACK)
tft.setBrightness(128);
#endif
break;
}
case DISPLAYOFF: {
#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
if (heltec_version == 3) {
digitalWrite(ST7735_BACKLIGHT_EN_V03, !TFT_BACKLIGHT_ON);
} else {
digitalWrite(ST7735_BACKLIGHT_EN_V05, !TFT_BACKLIGHT_ON);
}
#endif
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON);
#endif
#ifdef VTFT_CTRL_V03
if (heltec_version == 3) {
digitalWrite(VTFT_CTRL_V03, HIGH);
} else {
digitalWrite(VTFT_CTRL_V05, HIGH);
}
#endif
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, HIGH);
#endif
#ifndef M5STACK
#ifdef RAK14014
#elif !defined(M5STACK)
tft.setBrightness(0);
#endif
break;
@@ -404,7 +448,8 @@ void TFTDisplay::flipScreenVertically()
bool TFTDisplay::hasTouch(void)
{
#ifndef M5STACK
#ifdef RAK14014
#elif !defined(M5STACK)
return tft.touch() != nullptr;
#else
return false;
@@ -413,7 +458,8 @@ bool TFTDisplay::hasTouch(void)
bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
{
#ifndef M5STACK
#ifdef RAK14014
#elif !defined(M5STACK)
return tft.getTouch(x, y);
#else
return false;
@@ -434,11 +480,29 @@ bool TFTDisplay::connect()
#ifdef TFT_BL
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
pinMode(TFT_BL, OUTPUT);
// pinMode(PIN_3V3_EN, OUTPUT);
// digitalWrite(PIN_3V3_EN, HIGH);
LOG_INFO("Power to TFT Backlight\n");
#endif
#ifdef ST7735_BACKLIGHT_EN_V03
if (heltec_version == 3) {
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
pinMode(ST7735_BACKLIGHT_EN_V03, OUTPUT);
} else {
digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON);
pinMode(ST7735_BACKLIGHT_EN_V05, OUTPUT);
}
#endif
tft.init();
#if defined(M5STACK)
tft.setRotation(0);
#elif defined(RAK14014)
tft.setRotation(1);
tft.setSwapBytes(true);
// tft.fillScreen(TFT_BLACK);
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
tft.setRotation(1); // T-Deck has the TFT in landscape
#elif defined(T_WATCH_S3)
@@ -447,6 +511,7 @@ bool TFTDisplay::connect()
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
#endif
tft.fillScreen(TFT_BLACK);
return true;
}

181
src/input/BBQ10Keyboard.cpp Normal file
View File

@@ -0,0 +1,181 @@
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
#include <Arduino.h>
#include "BBQ10Keyboard.h"
#define _REG_VER 1
#define _REG_CFG 2
#define _REG_INT 3
#define _REG_KEY 4
#define _REG_BKL 5
#define _REG_DEB 6
#define _REG_FRQ 7
#define _REG_RST 8
#define _REG_FIF 9
#define _WRITE_MASK (1 << 7)
#define CFG_OVERFLOW_ON (1 << 0)
#define CFG_OVERFLOW_INT (1 << 1)
#define CFG_CAPSLOCK_INT (1 << 2)
#define CFG_NUMLOCK_INT (1 << 3)
#define CFG_KEY_INT (1 << 4)
#define CFG_PANIC_INT (1 << 5)
#define CFG_REPORT_MODS (1 << 6)
#define CFG_USE_MODS (1 << 7)
#define INT_OVERFLOW (1 << 0)
#define INT_CAPSLOCK (1 << 1)
#define INT_NUMLOCK (1 << 2)
#define INT_KEY (1 << 3)
#define INT_PANIC (1 << 4)
#define KEY_CAPSLOCK (1 << 5)
#define KEY_NUMLOCK (1 << 6)
#define KEY_COUNT_MASK (0x1F)
BBQ10Keyboard::BBQ10Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr) {}
void BBQ10Keyboard::begin(uint8_t addr, TwoWire *wire)
{
m_addr = addr;
m_wire = wire;
m_wire->begin();
reset();
}
void BBQ10Keyboard::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 BBQ10Keyboard::reset()
{
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(_REG_RST);
m_wire->endTransmission();
}
if (writeCallback) {
uint8_t data = 0;
writeCallback(m_addr, _REG_RST, &data, 0);
}
delay(100);
writeRegister(_REG_CFG, readRegister8(_REG_CFG) | CFG_REPORT_MODS);
delay(100);
}
void BBQ10Keyboard::attachInterrupt(uint8_t pin, void (*func)(void)) const
{
pinMode(pin, INPUT_PULLUP);
::attachInterrupt(digitalPinToInterrupt(pin), func, RISING);
}
void BBQ10Keyboard::detachInterrupt(uint8_t pin) const
{
::detachInterrupt(pin);
}
void BBQ10Keyboard::clearInterruptStatus()
{
writeRegister(_REG_INT, 0x00);
}
uint8_t BBQ10Keyboard::status() const
{
return readRegister8(_REG_KEY);
}
uint8_t BBQ10Keyboard::keyCount() const
{
return status() & KEY_COUNT_MASK;
}
BBQ10Keyboard::KeyEvent BBQ10Keyboard::keyEvent() const
{
KeyEvent event = {.key = '\0', .state = StateIdle};
if (keyCount() == 0)
return event;
const uint16_t buf = readRegister16(_REG_FIF);
event.key = buf >> 8;
event.state = KeyState(buf & 0xFF);
return event;
}
float BBQ10Keyboard::backlight() const
{
return readRegister8(_REG_BKL) / 255.0f;
}
void BBQ10Keyboard::setBacklight(float value)
{
writeRegister(_REG_BKL, value * 255);
}
uint8_t BBQ10Keyboard::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 BBQ10Keyboard::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 BBQ10Keyboard::writeRegister(uint8_t reg, uint8_t value)
{
uint8_t data[2];
data[0] = reg | _WRITE_MASK;
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);
}
}

51
src/input/BBQ10Keyboard.h Normal file
View File

@@ -0,0 +1,51 @@
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
#include "configuration.h"
#include <Wire.h>
#define KEY_MOD_ALT (0x1A)
#define KEY_MOD_SHL (0x1B)
#define KEY_MOD_SHR (0x1C)
#define KEY_MOD_SYM (0x1D)
class BBQ10Keyboard
{
public:
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
enum KeyState { StateIdle = 0, StatePress, StateLongPress, StateRelease };
struct KeyEvent {
char key;
KeyState state;
};
BBQ10Keyboard();
void begin(uint8_t addr = BBQ10_KB_ADDR, TwoWire *wire = &Wire);
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = BBQ10_KB_ADDR);
void reset(void);
void attachInterrupt(uint8_t pin, void (*func)(void)) const;
void detachInterrupt(uint8_t pin) const;
void clearInterruptStatus(void);
uint8_t status(void) const;
uint8_t keyCount(void) const;
KeyEvent keyEvent(void) const;
float backlight() const;
void setBacklight(float value);
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

@@ -5,12 +5,12 @@ RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() : RotaryEncoderInterruptBase("rotEnc1") {}
void RotaryEncoderInterruptImpl1::init()
bool RotaryEncoderInterruptImpl1::init()
{
if (!moduleConfig.canned_message.rotary1_enabled) {
// Input device is disabled.
disable();
return;
return false;
}
uint8_t pinA = moduleConfig.canned_message.inputbroker_pin_a;
@@ -25,6 +25,7 @@ void RotaryEncoderInterruptImpl1::init()
RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB,
RotaryEncoderInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this);
return true;
}
void RotaryEncoderInterruptImpl1::handleIntA()
@@ -38,4 +39,4 @@ void RotaryEncoderInterruptImpl1::handleIntB()
void RotaryEncoderInterruptImpl1::handleIntPressed()
{
rotaryEncoderInterruptImpl1->intPressHandler();
}
}

View File

@@ -12,7 +12,7 @@ class RotaryEncoderInterruptImpl1 : public RotaryEncoderInterruptBase
{
public:
RotaryEncoderInterruptImpl1();
void init();
bool init();
static void handleIntA();
static void handleIntB();
static void handleIntPressed();

View File

@@ -5,12 +5,12 @@ UpDownInterruptImpl1 *upDownInterruptImpl1;
UpDownInterruptImpl1::UpDownInterruptImpl1() : UpDownInterruptBase("upDown1") {}
void UpDownInterruptImpl1::init()
bool UpDownInterruptImpl1::init()
{
if (!moduleConfig.canned_message.updown1_enabled) {
// Input device is disabled.
return;
return false;
}
uint8_t pinUp = moduleConfig.canned_message.inputbroker_pin_a;
@@ -24,6 +24,7 @@ void UpDownInterruptImpl1::init()
UpDownInterruptBase::init(pinDown, pinUp, pinPress, eventDown, eventUp, eventPressed, UpDownInterruptImpl1::handleIntDown,
UpDownInterruptImpl1::handleIntUp, UpDownInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this);
return true;
}
void UpDownInterruptImpl1::handleIntDown()
@@ -37,4 +38,4 @@ void UpDownInterruptImpl1::handleIntUp()
void UpDownInterruptImpl1::handleIntPressed()
{
upDownInterruptImpl1->intPressHandler();
}
}

View File

@@ -5,10 +5,10 @@ class UpDownInterruptImpl1 : public UpDownInterruptBase
{
public:
UpDownInterruptImpl1();
void init();
bool init();
static void handleIntDown();
static void handleIntUp();
static void handleIntPressed();
};
extern UpDownInterruptImpl1 *upDownInterruptImpl1;
extern UpDownInterruptImpl1 *upDownInterruptImpl1;

View File

@@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
void CardKbI2cImpl::init()
{
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
if (cardkb_found.address == 0x00) {
disable();
return;
}

View File

@@ -30,7 +30,7 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len
int32_t KbI2cBase::runOnce()
{
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
if (cardkb_found.address == 0x00) {
// Input device is not detected.
return INT32_MAX;
}
@@ -41,11 +41,19 @@ int32_t KbI2cBase::runOnce()
#ifdef I2C_SDA1
LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
i2cBus = &Wire1;
if (cardkb_found.address == BBQ10_KB_ADDR) {
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire1);
Q10keyboard.setBacklight(0);
}
break;
#endif
case ScanI2C::WIRE:
LOG_DEBUG("Using I2C Bus 0 (the first one)\n");
i2cBus = &Wire;
if (cardkb_found.address == BBQ10_KB_ADDR) {
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire);
Q10keyboard.setBacklight(0);
}
break;
case ScanI2C::NO_I2C:
default:
@@ -53,7 +61,105 @@ int32_t KbI2cBase::runOnce()
}
}
if (kb_model == 0x02) {
switch (kb_model) {
case 0x11: { // BB Q10
int keyCount = Q10keyboard.keyCount();
while (keyCount--) {
const BBQ10Keyboard::KeyEvent key = Q10keyboard.keyEvent();
if ((key.key != 0x00) && (key.state == BBQ10Keyboard::StateRelease)) {
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.source = this->_originName;
switch (key.key) {
case 'p': // TAB
case 't': // TAB as well
if (is_sym) {
e.inputEvent = ANYKEY;
e.kbchar = 0x09; // TAB Scancode
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 'q': // ESC
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.kbchar = 0x1b;
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 0x08: // Back
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.kbchar = key.key;
break;
case 'e': // sym e
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.kbchar = 0xb5;
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 'x': // sym x
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.kbchar = 0xb6;
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 's': // sym s
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = 0x00; // tweak for destSelect
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 'f': // sym f
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = 0x00; // tweak for destSelect
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 0x13: // Code scanner says the SYM key is 0x13
is_sym = !is_sym;
break;
case 0x0a: // apparently Enter on Q10 is a line feed instead of carriage return
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
break;
case 0x00: // nopress
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
break;
default: // all other keys
e.inputEvent = ANYKEY;
e.kbchar = key.key;
is_sym = false; // reset sym state after second keypress
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
this->notifyObservers(&e);
}
}
}
break;
}
case 0x02: {
// RAK14004
uint8_t rDataBuf[8] = {0};
uint8_t PrintDataBuf = 0;
@@ -74,9 +180,12 @@ int32_t KbI2cBase::runOnce()
e.kbchar = PrintDataBuf;
this->notifyObservers(&e);
}
} else if (kb_model == 0x00 || kb_model == 0x10) {
// m5 cardkb and T-Deck
i2cBus->requestFrom(kb_model == 0x00 ? CARDKB_ADDR : TDECK_KB_ADDR, 1);
break;
}
case 0x00: // CARDKB
case 0x10: { // T-DECK
i2cBus->requestFrom((int)cardkb_found.address, 1);
while (i2cBus->available()) {
char c = i2cBus->read();
@@ -93,17 +202,19 @@ int32_t KbI2cBase::runOnce()
break;
case 0xb5: // Up
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.kbchar = 0xb5;
break;
case 0xb6: // Down
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.kbchar = 0xb6;
break;
case 0xb4: // Left
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = c;
e.kbchar = 0xb4;
break;
case 0xb7: // Right
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = c;
e.kbchar = 0xb7;
break;
case 0x0d: // Enter
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
@@ -121,7 +232,9 @@ int32_t KbI2cBase::runOnce()
this->notifyObservers(&e);
}
}
} else {
break;
}
default:
LOG_WARN("Unknown kb_model 0x%02x\n", kb_model);
}
return 300;

View File

@@ -1,5 +1,6 @@
#pragma once
#include "BBQ10Keyboard.h"
#include "InputBroker.h"
#include "Wire.h"
#include "concurrency/OSThread.h"
@@ -16,4 +17,7 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
const char *_originName;
TwoWire *i2cBus = 0;
BBQ10Keyboard Q10keyboard;
bool is_sym = false;
};

View File

@@ -29,6 +29,7 @@
#include "target_specific.h"
#include <Wire.h>
#include <memory>
#include <utility>
// #include <driver/rtc_io.h>
#include "mesh/eth/ethClient.h"
@@ -66,6 +67,14 @@ NRF52Bluetooth *nrf52Bluetooth;
#include "platform/portduino/SimRadio.h"
#endif
#ifdef ARCH_RASPBERRY_PI
#include "platform/portduino/PiHal.h"
#include "platform/portduino/PortduinoGlue.h"
#include <fstream>
#include <iostream>
#include <string>
#endif
#if HAS_BUTTON
#include "ButtonThread.h"
#endif
@@ -73,6 +82,7 @@ NRF52Bluetooth *nrf52Bluetooth;
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "AccelerometerThread.h"
#include "AmbientLightingThread.h"
#endif
using namespace concurrency;
@@ -121,18 +131,37 @@ uint32_t serialSinceMsec;
bool pmu_found;
// Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan
uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {
0}; // one is enough, missing elements will be initialized to 0 anyway.
// Array map of sensor types with i2c address and wire as we'll find in the i2c scan
std::pair<uint8_t, TwoWire *> nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {};
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
#ifdef ARCH_RASPBERRY_PI
void getPiMacAddr(uint8_t *dmac)
{
std::fstream macIdentity;
macIdentity.open("/sys/kernel/debug/bluetooth/hci0/identity", std::ios::in);
std::string macLine;
getline(macIdentity, macLine);
macIdentity.close();
dmac[0] = strtol(macLine.substr(0, 2).c_str(), NULL, 16);
dmac[1] = strtol(macLine.substr(3, 2).c_str(), NULL, 16);
dmac[2] = strtol(macLine.substr(6, 2).c_str(), NULL, 16);
dmac[3] = strtol(macLine.substr(9, 2).c_str(), NULL, 16);
dmac[4] = strtol(macLine.substr(12, 2).c_str(), NULL, 16);
dmac[5] = strtol(macLine.substr(15, 2).c_str(), NULL, 16);
}
#endif
const char *getDeviceName()
{
uint8_t dmac[6];
#ifdef ARCH_RASPBERRY_PI
getPiMacAddr(dmac);
#else
getMacAddr(dmac);
#endif
// Meshtastic_ab3c or Shortname_abcd
static char name[20];
snprintf(name, sizeof(name), "%02x%02x", dmac[4], dmac[5]);
@@ -145,6 +174,25 @@ const char *getDeviceName()
return name;
}
#ifdef VEXT_ENABLE_V03
#include <soc/rtc.h>
static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
{
const uint32_t cal_count = 1000;
uint32_t cali_val;
for (int i = 0; i < 5; ++i) {
cali_val = rtc_clk_cal(cal_clk, cal_count);
}
return cali_val;
}
int heltec_version = 3;
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
#endif
static int32_t ledBlinker()
{
static bool ledOn;
@@ -169,6 +217,7 @@ static OSThread *buttonThread;
uint32_t ButtonThread::longPressTime = 0;
#endif
static OSThread *accelerometerThread;
static OSThread *ambientLightingThread;
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
RadioInterface *rIf = NULL;
@@ -214,12 +263,59 @@ void setup()
digitalWrite(PIN_EINK_PWR_ON, HIGH);
#endif
#ifdef VEXT_ENABLE
#ifdef ST7735_BL_V03 // Heltec Wireless Tracker PCB Change Detect/Hack
rtc_clk_32k_enable(true);
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
if (CALIBRATE_ONE(RTC_CAL_32K_XTAL) != 0) {
rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
CALIBRATE_ONE(RTC_CAL_32K_XTAL);
}
if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
heltec_version = 3;
} else {
heltec_version = 5;
}
#endif
#if defined(VEXT_ENABLE_V03)
if (heltec_version == 3) {
pinMode(VEXT_ENABLE_V03, OUTPUT);
digitalWrite(VEXT_ENABLE_V03, 0); // turn on the display power
LOG_DEBUG("HELTEC Detect Tracker V1.0\n");
} else {
pinMode(VEXT_ENABLE_V05, OUTPUT);
digitalWrite(VEXT_ENABLE_V05, 1); // turn on the display power
LOG_DEBUG("HELTEC Detect Tracker V1.1\n");
}
#elif defined(VEXT_ENABLE)
pinMode(VEXT_ENABLE, OUTPUT);
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
#endif
#ifdef VGNSS_CTRL
#if defined(VGNSS_CTRL_V03)
if (heltec_version == 3) {
pinMode(VGNSS_CTRL_V03, OUTPUT);
digitalWrite(VGNSS_CTRL_V03, LOW);
} else {
pinMode(VGNSS_CTRL_V05, OUTPUT);
digitalWrite(VGNSS_CTRL_V05, LOW);
}
#endif
#if defined(VTFT_CTRL_V03)
if (heltec_version == 3) {
pinMode(VTFT_CTRL_V03, OUTPUT);
digitalWrite(VTFT_CTRL_V03, LOW);
} else {
pinMode(VTFT_CTRL_V05, OUTPUT);
digitalWrite(VTFT_CTRL_V05, LOW);
}
#endif
#if defined(VGNSS_CTRL)
pinMode(VGNSS_CTRL, OUTPUT);
digitalWrite(VGNSS_CTRL, LOW);
#endif
@@ -387,6 +483,10 @@ void setup()
// assign an arbitrary value to distinguish from other models
kb_model = 0x10;
break;
case ScanI2C::DeviceType::BBQ10KB:
// assign an arbitrary value to distinguish from other models
kb_model = 0x11;
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\n", kb_info.type);
@@ -405,14 +505,6 @@ void setup()
// Only one supported RGB LED currently
#ifdef HAS_NCP5623
rgb_found = i2cScanner->find(ScanI2C::DeviceType::NCP5623);
// Start the RGB LED at 50%
if (rgb_found.type == ScanI2C::NCP5623) {
rgb.begin();
rgb.setCurrent(10);
rgb.setColor(128, 128, 128);
}
#endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
@@ -427,7 +519,8 @@ void setup()
{ \
auto found = i2cScanner->find(SCANNER_T); \
if (found.type != ScanI2C::DeviceType::NONE) { \
nodeTelemetrySensorsMap[PB_T] = found.address.address; \
nodeTelemetrySensorsMap[PB_T].first = found.address.address; \
nodeTelemetrySensorsMap[PB_T].second = i2cScanner->fetchI2CBus(found.address); \
LOG_DEBUG("found i2c sensor %s\n", STRING(PB_T)); \
} \
}
@@ -437,6 +530,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31)
@@ -517,6 +611,12 @@ void setup()
}
#endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
if (rgb_found.type != ScanI2C::DeviceType::NONE) {
ambientLightingThread = new AmbientLightingThread(rgb_found.type);
}
#endif
#ifdef T_WATCH_S3
drv.begin();
drv.selectLibrary(1);
@@ -554,14 +654,12 @@ void setup()
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
gps = createGps();
gps = GPS::createGps();
if (gps) {
gpsStatus->observe(&gps->newStatus);
} else {
LOG_WARN("No GPS found - running without GPS\n");
LOG_DEBUG("Running without GPS.\n");
}
nodeStatus->observe(&nodeDB.newStatus);
service.init();
@@ -586,24 +684,43 @@ void setup()
screen->print("Started...\n");
// We have now loaded our saved preferences from flash
// ONCE we will factory reset the GPS for bug #327
if (gps && !devicestate.did_gps_reset) {
LOG_WARN("GPS FactoryReset requested\n");
if (gps->factoryReset()) { // If we don't succeed try again next time
devicestate.did_gps_reset = true;
nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
}
}
#ifdef SX126X_ANT_SW
// make analog PA vs not PA switch on SX126x eval board work properly
pinMode(SX126X_ANT_SW, OUTPUT);
digitalWrite(SX126X_ANT_SW, 1);
#endif
#ifdef HW_SPI1_DEVICE
#ifdef ARCH_RASPBERRY_PI
if (settingsMap[use_sx1262]) {
if (!rIf) {
PiHal *RadioLibHAL = new PiHal(1);
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
LOG_ERROR("Failed to find SX1262 radio\n");
delete rIf;
exit(EXIT_FAILURE);
} else {
LOG_INFO("SX1262 Radio init succeeded, using SX1262 radio\n");
}
}
} else if (settingsMap[use_rf95]) {
if (!rIf) {
PiHal *RadioLibHAL = new PiHal(1);
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
LOG_ERROR("Failed to find RF95 radio\n");
delete rIf;
rIf = NULL;
exit(EXIT_FAILURE);
} else {
LOG_INFO("RF95 Radio init succeeded, using RF95 radio\n");
}
}
}
#elif defined(HW_SPI1_DEVICE)
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
#else // HW_SPI1_DEVICE
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
@@ -649,7 +766,7 @@ void setup()
}
#endif
#if defined(USE_SX1262)
#if defined(USE_SX1262) && !defined(ARCH_RASPBERRY_PI)
if (!rIf) {
rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
@@ -751,7 +868,6 @@ void setup()
PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS
powerFSMthread = new PowerFSMThread();
// setBluetoothEnable(false); we now don't start bluetooth until we enter the proper state
setCPUFast(false); // 80MHz is fine for our slow peripherals
}

View File

@@ -56,6 +56,7 @@ extern graphics::Screen *screen;
// Return a human readable string of the form "Meshtastic_ab13"
const char *getDeviceName();
void getPiMacAddr(uint8_t *dmac);
extern uint32_t timeLastPowered;
@@ -64,6 +65,8 @@ extern uint32_t shutdownAtMsec;
extern uint32_t serialSinceMsec;
extern int heltec_version;
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
// This will suppress the current delay and instead try to run ASAP.
extern bool runASAP;

View File

@@ -1,5 +1,6 @@
#include "Channels.h"
#include "CryptoEngine.h"
#include "DisplayFormatters.h"
#include "NodeDB.h"
#include "configuration.h"
@@ -239,38 +240,9 @@ const char *Channels::getName(size_t chIndex)
const char *channelName = channelSettings.name;
if (!*channelName) { // emptystring
// Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case
// the app fucked up and forgot to set channelSettings.name
// the app effed up and forgot to set channelSettings.name
if (config.lora.use_preset) {
switch (config.lora.modem_preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
channelName = "ShortSlow";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
channelName = "ShortFast";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
channelName = "MediumSlow";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
channelName = "MediumFast";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
channelName = "LongSlow";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
channelName = "LongFast";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
channelName = "LongMod";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
channelName = "VLongSlow";
break;
default:
channelName = "Invalid";
break;
}
channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
} else {
channelName = "Custom";
}

View File

@@ -267,14 +267,22 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
void MeshService::sendToPhone(meshtastic_MeshPacket *p)
{
perhapsDecode(p);
if (toPhoneQueue.numFree() == 0) {
LOG_WARN("ToPhone queue is full, discarding oldest\n");
meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
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\n");
meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
} else {
LOG_WARN("ToPhone queue is full, dropping packet.\n");
releaseToPool(p);
return;
}
}
perhapsDecode(p);
assert(toPhoneQueue.enqueue(p, 0));
fromNum++;
}
@@ -327,21 +335,19 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
// load data from GPS object, will add timestamp + battery further down
pos = gps->p;
} else {
// The GPS has lost lock, if we are fixed position we should just keep using
// the old position
// The GPS has lost lock
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("onGPSchanged() - lost validLocation\n");
#endif
if (config.position.fixed_position) {
LOG_WARN("Using fixed position\n");
pos = ConvertToPosition(node->position);
}
}
// Used fixed position if configured regalrdless of GPS lock
if (config.position.fixed_position) {
LOG_WARN("Using fixed position\n");
pos = TypeConversions::ConvertToPosition(node->position);
}
// Finally add a fresh timestamp and battery level reading
// I KNOW this is redundant with refreshLocalMeshNode() above, but these are
// inexpensive nonblocking calls and can be refactored in due course
pos.time = getValidTime(RTCQualityGPS);
// Add a fresh timestamp
pos.time = getValidTime(RTCQualityFromNet);
// In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB)
LOG_DEBUG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i,

View File

@@ -48,6 +48,14 @@ class MeshService
uint32_t oldFromNum = 0;
public:
static bool isTextPayload(const meshtastic_MeshPacket *p)
{
if (moduleConfig.range_test.enabled && p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) {
return true;
}
return p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
p->decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP;
}
/// Called when some new packets have arrived from one of the radios
Observable<uint32_t> fromNumChanged;

View File

@@ -169,6 +169,14 @@ void NodeDB::installDefaultConfig()
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
config.lora.hop_limit = HOP_RELIABLE;
#ifdef PIN_GPS_EN
config.position.gps_en_gpio = PIN_GPS_EN;
#endif
#ifdef GPS_POWER_TOGGLE
config.device.disable_triple_click = false;
#else
config.device.disable_triple_click = true;
#endif
config.position.gps_enabled = true;
config.position.position_broadcast_smart_enabled = true;
config.position.broadcast_smart_minimum_distance = 100;
@@ -190,7 +198,9 @@ void NodeDB::installDefaultConfig()
: meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
// for backward compat, default position flags are ALT+MSL
config.position.position_flags =
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL);
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL |
meshtastic_Config_PositionConfig_PositionFlags_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING |
meshtastic_Config_PositionConfig_PositionFlags_DOP);
#ifdef T_WATCH_S3
config.display.screen_on_secs = 30;
@@ -244,10 +254,24 @@ void NodeDB::installDefaultModuleConfig()
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(moduleConfig.mqtt.address));
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password));
strncpy(moduleConfig.mqtt.root, default_mqtt_root, sizeof(moduleConfig.mqtt.root));
moduleConfig.mqtt.encryption_enabled = true;
moduleConfig.has_neighbor_info = true;
moduleConfig.neighbor_info.enabled = false;
moduleConfig.has_detection_sensor = true;
moduleConfig.detection_sensor.enabled = false;
moduleConfig.detection_sensor.detection_triggered_high = true;
moduleConfig.detection_sensor.minimum_broadcast_secs = 45;
moduleConfig.has_ambient_lighting = true;
moduleConfig.ambient_lighting.current = 10;
// Default to a color based on our node number
moduleConfig.ambient_lighting.red = (myNodeInfo.my_node_num & 0xFF0000) >> 16;
moduleConfig.ambient_lighting.green = (myNodeInfo.my_node_num & 0x00FF00) >> 8;
moduleConfig.ambient_lighting.blue = myNodeInfo.my_node_num & 0x0000FF;
initModuleConfigIntervals();
}
@@ -263,6 +287,15 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
} else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) {
moduleConfig.telemetry.environment_measurement_enabled = true;
moduleConfig.telemetry.environment_update_interval = 300;
} else if (role == meshtastic_Config_DeviceConfig_Role_TAK) {
config.device.node_info_broadcast_secs = ONE_DAY;
config.position.position_broadcast_smart_enabled = false;
config.position.position_broadcast_secs = ONE_DAY;
// Remove Altitude MSL from flags since CoTs use HAE (height above ellipsoid)
config.position.position_flags =
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_SPEED |
meshtastic_Config_PositionConfig_PositionFlags_HEADING | meshtastic_Config_PositionConfig_PositionFlags_DOP);
moduleConfig.telemetry.device_update_interval = ONE_DAY;
}
}
@@ -283,13 +316,40 @@ void NodeDB::installDefaultChannels()
void NodeDB::resetNodes()
{
devicestate.node_db_lite_count = 0;
memset(devicestate.node_db_lite, 0, sizeof(devicestate.node_db_lite));
devicestate.node_db_lite_count = 1;
std::fill(&devicestate.node_db_lite[1], &devicestate.node_db_lite[MAX_NUM_NODES - 1], meshtastic_NodeInfoLite());
saveDeviceStateToDisk();
if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
neighborInfoModule->resetNeighbors();
}
void NodeDB::removeNodeByNum(uint nodeNum)
{
int newPos = 0, removed = 0;
for (int i = 0; i < *numMeshNodes; i++) {
if (meshNodes[i].num != nodeNum)
meshNodes[newPos++] = meshNodes[i];
else
removed++;
}
*numMeshNodes -= removed;
LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Saving changes...\n", removed);
saveDeviceStateToDisk();
}
void NodeDB::cleanupMeshDB()
{
int newPos = 0, removed = 0;
for (int i = 0; i < *numMeshNodes; i++) {
if (meshNodes[i].has_user)
meshNodes[newPos++] = meshNodes[i];
else
removed++;
}
*numMeshNodes -= removed;
LOG_DEBUG("cleanupMeshDB purged %d entries\n", removed);
}
void NodeDB::installDefaultDeviceState()
{
LOG_INFO("Installing default DeviceState\n");
@@ -319,6 +379,7 @@ void NodeDB::init()
{
LOG_INFO("Initializing NodeDB\n");
loadFromDisk();
cleanupMeshDB();
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
uint32_t configCRC = crc32Buffer(&config, sizeof(config));
@@ -374,25 +435,25 @@ void NodeDB::init()
*/
void NodeDB::pickNewNodeNum()
{
NodeNum r = myNodeInfo.my_node_num;
#ifdef ARCH_RASPBERRY_PI
getPiMacAddr(ourMacAddr); // Make sure ourMacAddr is set
#else
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
#endif
// Pick an initial nodenum based on the macaddr
r = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
if (r == NODENUM_BROADCAST || r < NUM_RESERVED)
r = NUM_RESERVED; // don't pick a reserved node number
NodeNum nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
meshtastic_NodeInfoLite *found;
while ((found = getMeshNode(r)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr))) {
// FIXME: input for random() is int, so NODENUM_BROADCAST becomes -1
NodeNum n = random(NUM_RESERVED, NODENUM_BROADCAST); // try a new random choice
LOG_WARN("NOTE! Our desired nodenum 0x%x is in use, so trying for 0x%x\n", r, n);
r = n;
while ((nodeNum == NODENUM_BROADCAST || nodeNum < NUM_RESERVED) ||
((found = getMeshNode(nodeNum)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr)) != 0)) {
NodeNum candidate = random(NUM_RESERVED, LONG_MAX); // try a new random choice
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, so trying for 0x%x\n", nodeNum, candidate);
nodeNum = candidate;
}
LOG_WARN("Using nodenum 0x%x \n", nodeNum);
myNodeInfo.my_node_num = r;
myNodeInfo.my_node_num = nodeNum;
}
static const char *prefFileName = "/prefs/db.proto";
@@ -656,8 +717,8 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i,
p.longitude_i, p.altitude);
info->position = ConvertToPositionLite(p);
localPosition = p;
setLocalPosition(p);
info->position = TypeConversions::ConvertToPositionLite(p);
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) {
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
// (stop-gap fix for issue #900)
@@ -675,7 +736,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
uint32_t tmp_time = info->position.time;
// Next, update atomically
info->position = ConvertToPositionLite(p);
info->position = TypeConversions::ConvertToPositionLite(p);
// Last, restore any fields that may have been overwritten
if (!info->position.time)

View File

@@ -111,7 +111,7 @@ class NodeDB
/// Return the number of nodes we've heard from recently (within the last 2 hrs?)
size_t getNumOnlineMeshNodes();
void initConfigIntervals(), initModuleConfigIntervals(), resetNodes();
void initConfigIntervals(), initModuleConfigIntervals(), resetNodes(), removeNodeByNum(uint nodeNum);
bool factoryReset();
@@ -131,6 +131,13 @@ class NodeDB
meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
size_t getNumMeshNodes() { return *numMeshNodes; }
void setLocalPosition(meshtastic_Position position)
{
LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%i\n", position.latitude_i, position.longitude_i,
position.time);
localPosition = position;
}
private:
/// Find a node in our DB, create an empty NodeInfoLite if missing
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
@@ -146,6 +153,9 @@ class NodeDB
/// read our db from flash
void loadFromDisk();
/// purge db entries without user info
void cleanupMeshDB();
/// Reinit device state from scratch (not loading from disk)
void installDefaultDeviceState(), installDefaultChannels(), installDefaultConfig(), installDefaultModuleConfig();
};
@@ -189,11 +199,12 @@ extern NodeDB nodeDB;
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep
#define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60)
#define default_min_wake_secs 10
#define default_screen_on_secs 60 * 10
#define default_screen_on_secs IF_ROUTER(1, 60 * 10)
#define default_mqtt_address "mqtt.meshtastic.org"
#define default_mqtt_username "meshdev"
#define default_mqtt_password "large4cats"
#define default_mqtt_root "msh"
inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval)
{
@@ -209,6 +220,14 @@ inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t d
return defaultInterval * 1000;
}
inline uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue)
{
if (configured > 0)
return configured;
return defaultValue;
}
/// Sometimes we will have Position objects that only have a time, so check for
/// valid lat/lon
static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n)

View File

@@ -3,8 +3,8 @@
#include "Router.h"
#include <unordered_set>
/// We clear our old flood record five minute after we see the last of it
#define FLOOD_EXPIRE_TIME (5 * 60 * 1000L)
/// We clear our old flood record 10 minutes after we see the last of it
#define FLOOD_EXPIRE_TIME (10 * 60 * 1000L)
/**
* A record of a recent message broadcast

View File

@@ -155,11 +155,18 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// app not to send locations on our behalf.
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag;
fromRadioScratch.my_info = myNodeInfo;
state = STATE_SEND_NODEINFO;
state = STATE_SEND_METADATA;
service.refreshLocalMeshNode(); // Update my NodeInfo because the client will be asking for it soon.
break;
case STATE_SEND_METADATA:
LOG_INFO("getFromRadio=STATE_SEND_METADATA\n");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag;
fromRadioScratch.metadata = getDeviceMetadata();
state = STATE_SEND_NODEINFO;
break;
case STATE_SEND_NODEINFO: {
LOG_INFO("getFromRadio=STATE_SEND_NODEINFO\n");
@@ -283,6 +290,14 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
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:
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:
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag;
fromRadioScratch.moduleConfig.payload_variant.ambient_lighting = moduleConfig.ambient_lighting;
break;
default:
LOG_ERROR("Unknown module config type %d\n", config_state);
}
@@ -290,15 +305,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
config_state++;
// Advance when we have sent all of our ModuleConfig objects
if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) {
state = STATE_SEND_METADATA;
state = STATE_SEND_COMPLETE_ID;
config_state = 0;
}
break;
case STATE_SEND_METADATA:
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag;
fromRadioScratch.metadata = getDeviceMetadata();
state = STATE_SEND_COMPLETE_ID;
break;
case STATE_SEND_COMPLETE_ID:
LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag;
@@ -398,7 +409,7 @@ bool PhoneAPI::available()
if (nodeInfoForPhone.num == 0) {
auto nextNode = nodeDB.readNextMeshNode(readIndex);
if (nextNode) {
nodeInfoForPhone = ConvertToNodeInfo(nextNode);
nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(nextNode);
}
}
return true; // Always say we have something, because we might need to advance our state machine

View File

@@ -37,9 +37,6 @@ bool RF95Interface::init()
{
RadioLibInterface::init();
if (power == 0)
power = POWER_DEFAULT;
if (power > MAX_POWER) // This chip has lower power limits than some
power = MAX_POWER;

View File

@@ -384,27 +384,27 @@ void RadioInterface::applyModemConfig()
switch (loraConfig.modem_preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8;
cr = 5;
sf = 7;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8;
cr = 5;
sf = 8;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8;
cr = 5;
sf = 9;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8;
cr = 5;
sf = 10;
break;
default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal.
bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8;
cr = 5;
sf = 11;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
@@ -448,7 +448,9 @@ void RadioInterface::applyModemConfig()
power = myRegion->powerLimit;
if (power == 0)
power = 17; // Default to default power if we don't have a valid power
power = 17; // Default to this power level if we don't have a valid regional power limit (powerLimit of myRegion defaults
// to 0, currently no region has an actual power limit of 0 [dBm] so we can assume regions which have this
// variable set to 0 don't have a valid power limit)
// Set final tx_power back onto config
loraConfig.tx_power = (int8_t)power; // cppcheck-suppress assignmentAddressToInteger
@@ -534,8 +536,8 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
h->id = p->id;
h->channel = p->channel;
if (p->hop_limit > HOP_MAX) {
LOG_WARN("hop limit %d is too high, setting to %d\n", p->hop_limit, HOP_MAX);
p->hop_limit = HOP_MAX;
LOG_WARN("hop limit %d is too high, setting to %d\n", p->hop_limit, HOP_RELIABLE);
p->hop_limit = HOP_RELIABLE;
}
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0);

View File

@@ -56,7 +56,7 @@ class RadioInterface
float bw = 125;
uint8_t sf = 9;
uint8_t cr = 7;
uint8_t cr = 5;
/** Slottime is the minimum time to wait, consisting of:
- CAD duration (maximum of SX126x and SX127x);
- roundtrip air propagation time (assuming max. 30km between nodes);
@@ -223,4 +223,4 @@ class RadioInterface
};
/// Debug printing for packets
void printPacket(const char *prefix, const meshtastic_MeshPacket *p);
void printPacket(const char *prefix, const meshtastic_MeshPacket *p);

View File

@@ -249,29 +249,12 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
bool shouldActuallyEncrypt = true;
if (moduleConfig.mqtt.enabled) {
// check if we should send decrypted packets to mqtt
// truth table:
/* mqtt_server mqtt_encryption_enabled should_encrypt
* not set 0 1
* not set 1 1
* set 0 0
* set 1 1
*
* => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE
*/
if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) {
shouldActuallyEncrypt = false;
}
LOG_INFO("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt);
LOG_INFO("Should encrypt MQTT?: %d\n", moduleConfig.mqtt.encryption_enabled);
// the packet is currently in a decrypted state. send it now if they want decrypted packets
if (mqtt && !shouldActuallyEncrypt)
if (mqtt && !moduleConfig.mqtt.encryption_enabled)
mqtt->onSend(*p, chIndex);
}
@@ -284,7 +267,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
if (moduleConfig.mqtt.enabled) {
// the packet is now encrypted.
// check if we should send encrypted packets to mqtt
if (mqtt && shouldActuallyEncrypt)
if (mqtt && moduleConfig.mqtt.encryption_enabled)
mqtt->onSend(*p, chIndex);
}
}

View File

@@ -20,9 +20,6 @@ bool STM32WLE5JCInterface::init()
lora.setRfSwitchTable(rfswitch_pins, rfswitch_table);
if (power == 0)
power = STM32WLx_MAX_POWER;
if (power > STM32WLx_MAX_POWER) // This chip has lower power limits than some
power = STM32WLx_MAX_POWER;

View File

@@ -2,8 +2,12 @@
#include "configuration.h"
#include "error.h"
#include "mesh/NodeDB.h"
#ifdef ARCH_RASPBERRY_PI
#include "PortduinoGlue.h"
#endif
// Particular boards might define a different max power based on what their hardware can do
// Particular boards might define a different max power based on what their hardware can do, default to max power output if not
// specified (may be dangerous if using external PA and SX126x power config forgotten)
#ifndef SX126X_MAX_POWER
#define SX126X_MAX_POWER 22
#endif
@@ -26,20 +30,24 @@ template <typename T> bool SX126xInterface<T>::init()
pinMode(SX126X_POWER_EN, OUTPUT);
#endif
#ifndef SX126X_E22
float tcxoVoltage = 0; // None - we use an XTAL
// FIXME: correct logic to default to not using TCXO if no voltage is specified for SX126X_DIO3_TCXO_VOLTAGE
#if !defined(SX126X_DIO3_TCXO_VOLTAGE)
float tcxoVoltage =
0; // "TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip." per
// https://github.com/jgromes/RadioLib/blob/690a050ebb46e6097c5d00c371e961c1caa3b52e/src/modules/SX126x/SX126x.h#L471C26-L471C104
// (DIO3 is free to be used as an IRQ)
LOG_DEBUG("SX126X_DIO3_TCXO_VOLTAGE not defined, not using DIO3 as TCXO reference voltage\n");
#else
// Use DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575
float tcxoVoltage = 1.8;
float tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE;
LOG_DEBUG("SX126X_DIO3_TCXO_VOLTAGE defined, using DIO3 as TCXO reference voltage at %f V\n", SX126X_DIO3_TCXO_VOLTAGE);
// (DIO3 is not free to be used as an IRQ)
#endif
// FIXME: May want to set depending on a definition, currently all SX126x variant files use the DC-DC regulator option
bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
RadioLibInterface::init();
if (power == 0)
power = SX126X_MAX_POWER;
if (power > SX126X_MAX_POWER) // This chip has lower power limits than some
if (power > SX126X_MAX_POWER) // Clamp power to maximum defined level
power = SX126X_MAX_POWER;
limitPower();
@@ -54,49 +62,56 @@ template <typename T> bool SX126xInterface<T>::init()
LOG_INFO("Bandwidth set to %f\n", bw);
LOG_INFO("Power output set to %d\n", power);
// current limit was removed from module' ctor
// override default value (60 mA)
// Overriding current limit
// (https://github.com/jgromes/RadioLib/blob/690a050ebb46e6097c5d00c371e961c1caa3b52e/src/modules/SX126x/SX126x.cpp#L85) using
// value in SX126xInterface.h (currently 140 mA) It may or may not be neccessary, depending on how RadioLib functions, from
// SX1261/2 datasheet: OCP after setting DeviceSel with SetPaConfig(): SX1261 - 60 mA, SX1262 - 140 mA For the SX1268 the IC
// defaults to 140mA no matter the set power level, but RadioLib set it lower, this would need further checking Default values
// are: SX1262, SX1268: 0x38 (140 mA), SX1261: 0x18 (60 mA)
// FIXME: Not ideal to increase SX1261 current limit above 60mA as it can only transmit max 15dBm, should probably only do it
// if using SX1262 or SX1268
res = lora.setCurrentLimit(currentLimit);
LOG_DEBUG("Current limit set to %f\n", currentLimit);
LOG_DEBUG("Current limit set result %d\n", res);
#if defined(SX126X_E22)
// E22 Emulation explicitly requires DIO2 as RF switch, so set it to TRUE again for good measure. In case somebody defines
// SX126X_TX for an E22 Module
if (res == RADIOLIB_ERR_NONE) {
LOG_DEBUG("SX126X_E22 mode enabled. Setting DIO2 as RF Switch\n");
res = lora.setDio2AsRfSwitch(true);
#ifdef SX126X_DIO2_AS_RF_SWITCH
LOG_DEBUG("Setting DIO2 as RF switch\n");
bool dio2AsRfSwitch = true;
#elif defined(ARCH_RASPBERRY_PI)
bool dio2AsRfSwitch = false;
if (settingsMap[dio2_as_rf_switch]) {
LOG_DEBUG("Setting DIO2 as RF switch\n");
dio2AsRfSwitch = true;
}
#else
LOG_DEBUG("Setting DIO2 as not RF switch\n");
bool dio2AsRfSwitch = false;
#endif
if (res == RADIOLIB_ERR_NONE) {
res = lora.setDio2AsRfSwitch(dio2AsRfSwitch);
}
#if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
// If SX126X_TXEN is connected to the MCU, we are manually controlling RX and TX.
// But lora.begin (called above) sets Dio2 as RF switch control, which is not true here, so set it back to false.
if (res == RADIOLIB_ERR_NONE) {
LOG_DEBUG("SX126X_TXEN pin defined. Setting RF Switch: RXEN=%i, TXEN=%i\n", SX126X_RXEN, SX126X_TXEN);
res = lora.setDio2AsRfSwitch(false);
lora.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
}
#elif defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC && defined(E22_TXEN_CONNECTED_TO_DIO2))
// Otherwise, if SX126X_RXEN is connected to the MCU, and E22_TXEN_CONNECTED_TO_DIO2 is defined, we are letting the
// E22 control RX and TX via DIO2. In this configuration, the E22's TXEN and DIO2 pins are connected to each other,
// but not to the MCU.
// However, we must still connect the E22's RXEN pin to the MCU, define SX126X_RXEN accordingly, and then call
// setRfSwitchPins, otherwise RX sensitivity (observed via RSSI) is greatly diminished.
LOG_DEBUG("SX126X_RXEN and E22_TXEN_CONNECTED_TO_DIO2 are defined; value of res: %d", res);
if (res == RADIOLIB_ERR_NONE) {
LOG_DEBUG("SX126X_TXEN is RADIOLIB_NC, but SX126X_RXEN and E22_TXEN_CONNECTED_TO_DIO2 are both defined; calling "
"lora.setRfSwitchPins.");
lora.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
}
// If a pin isn't defined, we set it to RADIOLIB_NC, it is safe to always do external RF switching with RADIOLIB_NC as it has
// no effect
#ifndef SX126X_RXEN
#define SX126X_RXEN RADIOLIB_NC
LOG_DEBUG("SX126X_RXEN not defined, defaulting to RADIOLIB_NC\n");
#endif
#ifndef SX126X_TXEN
#define SX126X_TXEN RADIOLIB_NC
LOG_DEBUG("SX126X_TXEN not defined, defaulting to RADIOLIB_NC\n");
#endif
if (res == RADIOLIB_ERR_NONE) {
LOG_DEBUG("Using MCU pin %i as RXEN and pin %i as TXEN to control RF switching\n", SX126X_RXEN, SX126X_TXEN);
lora.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
}
if (config.lora.sx126x_rx_boosted_gain) {
uint16_t result = lora.setRxBoostedGainMode(true);
LOG_INFO("Set Rx Boosted Gain mode; result: %d\n", result);
LOG_INFO("Set RX gain to boosted mode; result: %d\n", result);
} else {
uint16_t result = lora.setRxBoostedGainMode(false);
LOG_INFO("Set Rx Power Saving Gain mode; result: %d\n", result);
LOG_INFO("Set RX gain to power saving mode (boosted mode off); result: %d\n", result);
}
#if 0
@@ -265,7 +280,7 @@ template <typename T> bool SX126xInterface<T>::isChannelActive()
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
template <typename T> bool SX126xInterface<T>::isActivelyReceiving()
{
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
// received and handled the interrupt for reading the packet/handling errors.
uint16_t irq = lora.getIrqStatus();
@@ -296,7 +311,7 @@ template <typename T> bool SX126xInterface<T>::sleep()
{
// Not keeping config is busted - next time nrf52 board boots lora sending fails tcxo related? - see datasheet
// \todo Display actual typename of the adapter, not just `SX126x`
LOG_DEBUG("sx126x entering sleep mode (FIXME, don't keep config)\n");
LOG_DEBUG("SX126x entering sleep mode (FIXME, don't keep config)\n");
setStandby(); // Stop any pending operations
// turn off TCXO if it was powered

View File

@@ -42,9 +42,6 @@ template <typename T> bool SX128xInterface<T>::init()
RadioLibInterface::init();
if (power == 0)
power = SX128X_MAX_POWER;
if (power > SX128X_MAX_POWER) // This chip has lower power limits than some
power = SX128X_MAX_POWER;

View File

@@ -0,0 +1,55 @@
#include "TypeConversions.h"
#include "mesh/generated/meshtastic/deviceonly.pb.h"
#include "mesh/generated/meshtastic/mesh.pb.h"
meshtastic_NodeInfo TypeConversions::ConvertToNodeInfo(const meshtastic_NodeInfoLite *lite)
{
meshtastic_NodeInfo info = meshtastic_NodeInfo_init_default;
info.num = lite->num;
info.snr = lite->snr;
info.last_heard = lite->last_heard;
info.channel = lite->channel;
if (lite->has_position) {
info.has_position = true;
info.position.latitude_i = lite->position.latitude_i;
info.position.longitude_i = lite->position.longitude_i;
info.position.altitude = lite->position.altitude;
info.position.location_source = lite->position.location_source;
info.position.time = lite->position.time;
}
if (lite->has_user) {
info.has_user = true;
info.user = lite->user;
}
if (lite->has_device_metrics) {
info.has_device_metrics = true;
info.device_metrics = lite->device_metrics;
}
return info;
}
meshtastic_PositionLite TypeConversions::ConvertToPositionLite(meshtastic_Position position)
{
meshtastic_PositionLite lite = meshtastic_PositionLite_init_default;
lite.latitude_i = position.latitude_i;
lite.longitude_i = position.longitude_i;
lite.altitude = position.altitude;
lite.location_source = position.location_source;
lite.time = position.time;
return lite;
}
meshtastic_Position TypeConversions::ConvertToPosition(meshtastic_PositionLite lite)
{
meshtastic_Position position = meshtastic_Position_init_default;
position.latitude_i = lite.latitude_i;
position.longitude_i = lite.longitude_i;
position.altitude = lite.altitude;
position.location_source = lite.location_source;
position.time = lite.time;
return position;
}

View File

@@ -1,54 +1,13 @@
#include "mesh/generated/meshtastic/deviceonly.pb.h"
#include "mesh/generated/meshtastic/mesh.pb.h"
inline static meshtastic_NodeInfo ConvertToNodeInfo(const meshtastic_NodeInfoLite *lite)
#pragma once
#include "NodeDB.h"
class TypeConversions
{
meshtastic_NodeInfo info = meshtastic_NodeInfo_init_default;
info.num = lite->num;
info.snr = lite->snr;
info.last_heard = lite->last_heard;
info.channel = lite->channel;
if (lite->has_position) {
info.has_position = true;
info.position.latitude_i = lite->position.latitude_i;
info.position.longitude_i = lite->position.longitude_i;
info.position.altitude = lite->position.altitude;
info.position.location_source = lite->position.location_source;
info.position.time = lite->position.time;
}
if (lite->has_user) {
info.has_user = true;
info.user = lite->user;
}
if (lite->has_device_metrics) {
info.has_device_metrics = true;
info.device_metrics = lite->device_metrics;
}
return info;
}
inline static meshtastic_PositionLite ConvertToPositionLite(meshtastic_Position position)
{
meshtastic_PositionLite lite = meshtastic_PositionLite_init_default;
lite.latitude_i = position.latitude_i;
lite.longitude_i = position.longitude_i;
lite.altitude = position.altitude;
lite.location_source = position.location_source;
lite.time = position.time;
return lite;
}
inline static meshtastic_Position ConvertToPosition(meshtastic_PositionLite lite)
{
meshtastic_Position position = meshtastic_Position_init_default;
position.latitude_i = lite.latitude_i;
position.longitude_i = lite.longitude_i;
position.altitude = lite.altitude;
position.location_source = lite.location_source;
position.time = lite.time;
return position;
}
public:
static meshtastic_NodeInfo ConvertToNodeInfo(const meshtastic_NodeInfoLite *lite);
static meshtastic_PositionLite ConvertToPositionLite(meshtastic_Position position);
static meshtastic_Position ConvertToPosition(meshtastic_PositionLite lite);
};

View File

@@ -57,7 +57,9 @@ typedef enum _meshtastic_AdminMessage_ModuleConfigType {
/* TODO: REPLACE */
meshtastic_AdminMessage_ModuleConfigType_NEIGHBORINFO_CONFIG = 9,
/* TODO: REPLACE */
meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG = 10
meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG = 10,
/* TODO: REPLACE */
meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG = 11
} meshtastic_AdminMessage_ModuleConfigType;
/* Struct definitions */
@@ -143,6 +145,8 @@ typedef struct _meshtastic_AdminMessage {
char set_canned_message_module_messages[201];
/* Set the ringtone for ExternalNotification. */
char set_ringtone_message[231];
/* Remove the node by the specified node-num from the NodeDB on the device */
uint32_t remove_by_nodenum;
/* Begins an edit transaction for config, module config, owner, and channel settings changes
This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */
bool begin_edit_settings;
@@ -176,8 +180,8 @@ extern "C" {
#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_BLUETOOTH_CONFIG+1))
#define _meshtastic_AdminMessage_ModuleConfigType_MIN meshtastic_AdminMessage_ModuleConfigType_MQTT_CONFIG
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG+1))
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG+1))
#define meshtastic_AdminMessage_payload_variant_get_config_request_ENUMTYPE meshtastic_AdminMessage_ConfigType
#define meshtastic_AdminMessage_payload_variant_get_module_config_request_ENUMTYPE meshtastic_AdminMessage_ModuleConfigType
@@ -224,6 +228,7 @@ extern "C" {
#define meshtastic_AdminMessage_set_module_config_tag 35
#define meshtastic_AdminMessage_set_canned_message_module_messages_tag 36
#define meshtastic_AdminMessage_set_ringtone_message_tag 37
#define meshtastic_AdminMessage_remove_by_nodenum_tag 38
#define meshtastic_AdminMessage_begin_edit_settings_tag 64
#define meshtastic_AdminMessage_commit_edit_settings_tag 65
#define meshtastic_AdminMessage_reboot_ota_seconds_tag 95
@@ -260,6 +265,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34)
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_module_config,set_module_config), 35) \
X(a, STATIC, ONEOF, STRING, (payload_variant,set_canned_message_module_messages,set_canned_message_module_messages), 36) \
X(a, STATIC, ONEOF, STRING, (payload_variant,set_ringtone_message,set_ringtone_message), 37) \
X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_by_nodenum,remove_by_nodenum), 38) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \
X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \

View File

@@ -30,11 +30,20 @@ typedef enum _meshtastic_Config_DeviceConfig_Role {
or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate. */
meshtastic_Config_DeviceConfig_Role_REPEATER = 4,
/* Tracker device role
Position Mesh packets will be prioritized higher and sent more frequently by default. */
Position Mesh packets will be prioritized higher and sent more frequently by default.
When used in conjunction with power.is_power_saving = true, nodes will wake up,
send position, and then sleep for position.position_broadcast_secs seconds. */
meshtastic_Config_DeviceConfig_Role_TRACKER = 5,
/* Sensor device role
Telemetry Mesh packets will be prioritized higher and sent more frequently by default. */
meshtastic_Config_DeviceConfig_Role_SENSOR = 6
Telemetry Mesh packets will be prioritized higher and sent more frequently by default.
When used in conjunction with power.is_power_saving = true, nodes will wake up,
send environment telemetry, and then sleep for telemetry.environment_update_interval seconds. */
meshtastic_Config_DeviceConfig_Role_SENSOR = 6,
/* TAK device role
Used for nodes dedicated for connection to an ATAK EUD.
Turns off many of the routine broadcasts to favor CoT packet stream
from the Meshtastic ATAK plugin -> IMeshService -> Node */
meshtastic_Config_DeviceConfig_Role_TAK = 7
} meshtastic_Config_DeviceConfig_Role;
/* Defines the device's behavior for how messages are rebroadcast */
@@ -51,8 +60,9 @@ typedef enum _meshtastic_Config_DeviceConfig_RebroadcastMode {
} meshtastic_Config_DeviceConfig_RebroadcastMode;
/* Bit field of boolean configuration options, indicating which optional
fields to include when assembling POSITION messages
Longitude and latitude are always included (also time if GPS-synced)
fields to include when assembling POSITION messages.
Longitude, latitude, altitude, speed, heading, and DOP
are always included (also time if GPS-synced)
NOTE: the more fields are included, the larger the message will be -
leading to longer airtime and a higher risk of packet loss */
typedef enum _meshtastic_Config_PositionConfig_PositionFlags {
@@ -236,6 +246,8 @@ typedef struct _meshtastic_Config_DeviceConfig {
/* If true, device is considered to be "managed" by a mesh administrator
Clients should then limit available configuration and administrative options inside the user interface */
bool is_managed;
/* Disables the triple-press of user button to enable or disable GPS */
bool disable_triple_click;
} meshtastic_Config_DeviceConfig;
/* Position Config */
@@ -269,8 +281,10 @@ typedef struct _meshtastic_Config_PositionConfig {
uint32_t tx_gpio;
/* The minimum distance in meters traveled (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */
uint32_t broadcast_smart_minimum_distance;
/* The minumum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */
/* The minimum number of seconds (since the last send) before we can send a position to the mesh if position_broadcast_smart_enabled */
uint32_t broadcast_smart_minimum_interval_secs;
/* (Re)define PIN_GPS_EN for your board. */
uint32_t gps_en_gpio;
} meshtastic_Config_PositionConfig;
/* Power Config\
@@ -329,7 +343,7 @@ typedef struct _meshtastic_Config_NetworkConfig {
acquire an address via DHCP */
char wifi_ssid[33];
/* If set, will be use to authenticate to the named wifi */
char wifi_psk[64];
char wifi_psk[65];
/* NTP server to use if WiFi is conneced, defaults to `0.pool.ntp.org` */
char ntp_server[33];
/* Enable Ethernet */
@@ -398,7 +412,8 @@ typedef struct _meshtastic_Config_LoRaConfig {
/* The region code for the radio (US, CN, EU433, etc...) */
meshtastic_Config_LoRaConfig_RegionCode region;
/* Maximum number of hops. This can't be greater than 7.
Default of 3 */
Default of 3
Attempting to set a value > 7 results in the default */
uint32_t hop_limit;
/* Disable TX from the LoRa radio. Useful for hot-swapping antennas and other tests.
Defaults to false */
@@ -464,8 +479,8 @@ extern "C" {
/* Helper constants for enums */
#define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_SENSOR
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_SENSOR+1))
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_TAK
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_TAK+1))
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY
@@ -529,8 +544,8 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}}
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0}
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0}
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""}
#define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
@@ -538,8 +553,8 @@ extern "C" {
#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0}
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0}
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""}
#define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
@@ -557,6 +572,7 @@ extern "C" {
#define meshtastic_Config_DeviceConfig_node_info_broadcast_secs_tag 7
#define meshtastic_Config_DeviceConfig_double_tap_as_button_press_tag 8
#define meshtastic_Config_DeviceConfig_is_managed_tag 9
#define meshtastic_Config_DeviceConfig_disable_triple_click_tag 10
#define meshtastic_Config_PositionConfig_position_broadcast_secs_tag 1
#define meshtastic_Config_PositionConfig_position_broadcast_smart_enabled_tag 2
#define meshtastic_Config_PositionConfig_fixed_position_tag 3
@@ -568,6 +584,7 @@ extern "C" {
#define meshtastic_Config_PositionConfig_tx_gpio_tag 9
#define meshtastic_Config_PositionConfig_broadcast_smart_minimum_distance_tag 10
#define meshtastic_Config_PositionConfig_broadcast_smart_minimum_interval_secs_tag 11
#define meshtastic_Config_PositionConfig_gps_en_gpio_tag 12
#define meshtastic_Config_PowerConfig_is_power_saving_tag 1
#define meshtastic_Config_PowerConfig_on_battery_shutdown_after_secs_tag 2
#define meshtastic_Config_PowerConfig_adc_multiplier_override_tag 3
@@ -652,7 +669,8 @@ X(a, STATIC, SINGULAR, UINT32, buzzer_gpio, 5) \
X(a, STATIC, SINGULAR, UENUM, rebroadcast_mode, 6) \
X(a, STATIC, SINGULAR, UINT32, node_info_broadcast_secs, 7) \
X(a, STATIC, SINGULAR, BOOL, double_tap_as_button_press, 8) \
X(a, STATIC, SINGULAR, BOOL, is_managed, 9)
X(a, STATIC, SINGULAR, BOOL, is_managed, 9) \
X(a, STATIC, SINGULAR, BOOL, disable_triple_click, 10)
#define meshtastic_Config_DeviceConfig_CALLBACK NULL
#define meshtastic_Config_DeviceConfig_DEFAULT NULL
@@ -667,7 +685,8 @@ X(a, STATIC, SINGULAR, UINT32, position_flags, 7) \
X(a, STATIC, SINGULAR, UINT32, rx_gpio, 8) \
X(a, STATIC, SINGULAR, UINT32, tx_gpio, 9) \
X(a, STATIC, SINGULAR, UINT32, broadcast_smart_minimum_distance, 10) \
X(a, STATIC, SINGULAR, UINT32, broadcast_smart_minimum_interval_secs, 11)
X(a, STATIC, SINGULAR, UINT32, broadcast_smart_minimum_interval_secs, 11) \
X(a, STATIC, SINGULAR, UINT32, gps_en_gpio, 12)
#define meshtastic_Config_PositionConfig_CALLBACK NULL
#define meshtastic_Config_PositionConfig_DEFAULT NULL
@@ -767,14 +786,14 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
/* Maximum encoded size of messages (where known) */
#define meshtastic_Config_BluetoothConfig_size 10
#define meshtastic_Config_DeviceConfig_size 30
#define meshtastic_Config_DeviceConfig_size 32
#define meshtastic_Config_DisplayConfig_size 28
#define meshtastic_Config_LoRaConfig_size 77
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
#define meshtastic_Config_NetworkConfig_size 195
#define meshtastic_Config_PositionConfig_size 54
#define meshtastic_Config_NetworkConfig_size 196
#define meshtastic_Config_PositionConfig_size 60
#define meshtastic_Config_PowerConfig_size 40
#define meshtastic_Config_size 198
#define meshtastic_Config_size 199
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -316,7 +316,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
#define meshtastic_DeviceState_size 16854
#define meshtastic_NodeInfoLite_size 151
#define meshtastic_NodeRemoteHardwarePin_size 29
#define meshtastic_OEMStore_size 3148
#define meshtastic_OEMStore_size 3231
#define meshtastic_PositionLite_size 28
#ifdef __cplusplus

View File

@@ -75,6 +75,12 @@ typedef struct _meshtastic_LocalModuleConfig {
/* The part of the config that is specific to the Neighbor Info module */
bool has_neighbor_info;
meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info;
/* The part of the config that is specific to the Ambient Lighting module */
bool has_ambient_lighting;
meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting;
/* The part of the config that is specific to the Detection Sensor module */
bool has_detection_sensor;
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
} meshtastic_LocalModuleConfig;
@@ -84,9 +90,9 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_LocalConfig_init_default {false, meshtastic_Config_DeviceConfig_init_default, false, meshtastic_Config_PositionConfig_init_default, false, meshtastic_Config_PowerConfig_init_default, false, meshtastic_Config_NetworkConfig_init_default, false, meshtastic_Config_DisplayConfig_init_default, false, meshtastic_Config_LoRaConfig_init_default, false, meshtastic_Config_BluetoothConfig_init_default, 0}
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default}
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_default, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_default}
#define meshtastic_LocalConfig_init_zero {false, meshtastic_Config_DeviceConfig_init_zero, false, meshtastic_Config_PositionConfig_init_zero, false, meshtastic_Config_PowerConfig_init_zero, false, meshtastic_Config_NetworkConfig_init_zero, false, meshtastic_Config_DisplayConfig_init_zero, false, meshtastic_Config_LoRaConfig_init_zero, false, meshtastic_Config_BluetoothConfig_init_zero, 0}
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero}
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_zero, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_zero}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_LocalConfig_device_tag 1
@@ -108,6 +114,8 @@ extern "C" {
#define meshtastic_LocalModuleConfig_audio_tag 9
#define meshtastic_LocalModuleConfig_remote_hardware_tag 10
#define meshtastic_LocalModuleConfig_neighbor_info_tag 11
#define meshtastic_LocalModuleConfig_ambient_lighting_tag 12
#define meshtastic_LocalModuleConfig_detection_sensor_tag 13
/* Struct field encoding specification for nanopb */
#define meshtastic_LocalConfig_FIELDLIST(X, a) \
@@ -140,7 +148,9 @@ X(a, STATIC, OPTIONAL, MESSAGE, canned_message, 7) \
X(a, STATIC, SINGULAR, UINT32, version, 8) \
X(a, STATIC, OPTIONAL, MESSAGE, audio, 9) \
X(a, STATIC, OPTIONAL, MESSAGE, remote_hardware, 10) \
X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11)
X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11) \
X(a, STATIC, OPTIONAL, MESSAGE, ambient_lighting, 12) \
X(a, STATIC, OPTIONAL, MESSAGE, detection_sensor, 13)
#define meshtastic_LocalModuleConfig_CALLBACK NULL
#define meshtastic_LocalModuleConfig_DEFAULT NULL
#define meshtastic_LocalModuleConfig_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
@@ -153,6 +163,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11)
#define meshtastic_LocalModuleConfig_audio_MSGTYPE meshtastic_ModuleConfig_AudioConfig
#define meshtastic_LocalModuleConfig_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig
#define meshtastic_LocalModuleConfig_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig
#define meshtastic_LocalModuleConfig_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
#define meshtastic_LocalModuleConfig_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
extern const pb_msgdesc_t meshtastic_LocalConfig_msg;
extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
@@ -162,8 +174,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */
#define meshtastic_LocalConfig_size 455
#define meshtastic_LocalModuleConfig_size 547
#define meshtastic_LocalConfig_size 464
#define meshtastic_LocalModuleConfig_size 621
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -111,6 +111,10 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_T_WATCH_S3 = 51,
/* Bobricius Picomputer with ESP32-S3 CPU, Keyboard and IPS display */
meshtastic_HardwareModel_PICOMPUTER_S3 = 52,
/* Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa */
meshtastic_HardwareModel_HELTEC_HT62 = 53,
/* EBYTE SPI LoRa module and ESP32-S3 */
meshtastic_HardwareModel_EBYTE_ESP32_S3 = 54,
/* ------------------------------------------------------------------------------------------------------------------------------------------
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
------------------------------------------------------------------------------------------------------------------------------------------ */
@@ -153,7 +157,7 @@ typedef enum _meshtastic_CriticalErrorCode {
/* Radio transmit hardware failure. We sent data to the radio chip, but it didn't
reply with an interrupt. */
meshtastic_CriticalErrorCode_TRANSMIT_FAILED = 8,
/* We detected that the main CPU voltage dropped below the minumum acceptable value */
/* We detected that the main CPU voltage dropped below the minimum acceptable value */
meshtastic_CriticalErrorCode_BROWNOUT = 9,
/* Selftest of SX1262 radio chip failed */
meshtastic_CriticalErrorCode_SX1262_FAILURE = 10,
@@ -297,9 +301,8 @@ typedef struct _meshtastic_Position {
/* In meters above MSL (but see issue #359) */
int32_t altitude;
/* This is usually not sent over the mesh (to save space), but it is sent
from the phone so that the local device can set its RTC If it is sent over
the mesh (because there are devices on the mesh without GPS), it will only
be sent by devices which has a hardware GPS clock.
from the phone so that the local device can set its time if it is sent over
the mesh (because there are devices on the mesh without GPS or RTC).
seconds since 1970 */
uint32_t time;
/* TODO: REPLACE */

View File

@@ -18,6 +18,9 @@ PB_BIND(meshtastic_ModuleConfig_RemoteHardwareConfig, meshtastic_ModuleConfig_Re
PB_BIND(meshtastic_ModuleConfig_NeighborInfoConfig, meshtastic_ModuleConfig_NeighborInfoConfig, AUTO)
PB_BIND(meshtastic_ModuleConfig_DetectionSensorConfig, meshtastic_ModuleConfig_DetectionSensorConfig, AUTO)
PB_BIND(meshtastic_ModuleConfig_AudioConfig, meshtastic_ModuleConfig_AudioConfig, AUTO)

View File

@@ -125,6 +125,33 @@ typedef struct _meshtastic_ModuleConfig_NeighborInfoConfig {
uint32_t update_interval;
} meshtastic_ModuleConfig_NeighborInfoConfig;
/* Detection Sensor Module Config */
typedef struct _meshtastic_ModuleConfig_DetectionSensorConfig {
/* Whether the Module is enabled */
bool enabled;
/* Interval in seconds of how often we can send a message to the mesh when a state change is detected */
uint32_t minimum_broadcast_secs;
/* Interval in seconds of how often we should send a message to the mesh with the current state regardless of changes
When set to 0, only state changes will be broadcasted
Works as a sort of status heartbeat for peace of mind */
uint32_t state_broadcast_secs;
/* Send ASCII bell with alert message
Useful for triggering ext. notification on bell */
bool send_bell;
/* Friendly name used to format message sent to mesh
Example: A name "Motion" would result in a message "Motion detected"
Maximum length of 20 characters */
char name[20];
/* GPIO pin to monitor for state changes */
uint8_t monitor_pin;
/* Whether or not the GPIO pin state detection is triggered on HIGH (1)
Otherwise LOW (0) */
bool detection_triggered_high;
/* Whether or not use INPUT_PULLUP mode for GPIO pin
Only applicable if the board uses pull-up resistors on the pin */
bool use_pullup;
} meshtastic_ModuleConfig_DetectionSensorConfig;
/* Audio Config for codec2 voice */
typedef struct _meshtastic_ModuleConfig_AudioConfig {
/* Whether Audio is enabled */
@@ -205,6 +232,9 @@ typedef struct _meshtastic_ModuleConfig_ExternalNotificationConfig {
Default is 0 which means don't repeat at all. 60 would mean blink
and/or beep for 60 seconds */
uint16_t nag_timeout;
/* When true, enables devices with native I2S audio output to use the RTTTL over speaker like a buzzer
T-Watch S3 and T-Deck for example have this capability */
bool use_i2s_as_buzzer;
} meshtastic_ModuleConfig_ExternalNotificationConfig;
/* Store and Forward Module Config */
@@ -251,6 +281,15 @@ typedef struct _meshtastic_ModuleConfig_TelemetryConfig {
/* Interval in seconds of how often we should try to send our
air quality metrics to the mesh */
uint32_t air_quality_interval;
/* Interval in seconds of how often we should try to send our
air quality metrics to the mesh */
bool power_measurement_enabled;
/* Interval in seconds of how often we should try to send our
air quality metrics to the mesh */
uint32_t power_update_interval;
/* Interval in seconds of how often we should try to send our
air quality metrics to the mesh */
bool power_screen_enabled;
} meshtastic_ModuleConfig_TelemetryConfig;
/* TODO: REPLACE */
@@ -286,13 +325,14 @@ Initially created for the RAK14001 RGB LED module. */
typedef struct _meshtastic_ModuleConfig_AmbientLightingConfig {
/* Sets LED to on or off. */
bool led_state;
/* Sets the overall current for the LED, firmware side range for the RAK14001 is 1-31, but users should be given a range of 0-100% */
/* Sets the current for the LED output. Default is 10. */
uint8_t current;
uint8_t red; /* Red level */
/* Sets the green level of the LED, firmware side values are 0-255, but users should be given a range of 0-100% */
uint8_t green; /* Green level */
/* Sets the blue level of the LED, firmware side values are 0-255, but users should be given a range of 0-100% */
uint8_t blue; /* Blue level */
/* Sets the red LED level. Values are 0-255. */
uint8_t red;
/* Sets the green LED level. Values are 0-255. */
uint8_t green;
/* Sets the blue LED level. Values are 0-255. */
uint8_t blue;
} meshtastic_ModuleConfig_AmbientLightingConfig;
/* A GPIO pin definition for remote hardware module */
@@ -342,6 +382,8 @@ typedef struct _meshtastic_ModuleConfig {
meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info;
/* TODO: REPLACE */
meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting;
/* TODO: REPLACE */
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
} payload_variant;
} meshtastic_ModuleConfig;
@@ -375,6 +417,7 @@ extern "C" {
#define meshtastic_ModuleConfig_AudioConfig_bitrate_ENUMTYPE meshtastic_ModuleConfig_AudioConfig_Audio_Baud
#define meshtastic_ModuleConfig_SerialConfig_baud_ENUMTYPE meshtastic_ModuleConfig_SerialConfig_Serial_Baud
@@ -397,12 +440,13 @@ extern "C" {
#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, "", 0}
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_default {0, 0, 0, {meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default}}
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0}
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_default {0, 0, 0, 0, "", 0, 0, 0}
#define meshtastic_ModuleConfig_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
#define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN}
@@ -410,12 +454,13 @@ extern "C" {
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0}
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero {0, 0, 0, {meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero}}
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0}
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_zero {0, 0, 0, 0, "", 0, 0, 0}
#define meshtastic_ModuleConfig_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0}
#define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN}
@@ -432,6 +477,14 @@ extern "C" {
#define meshtastic_ModuleConfig_MQTTConfig_proxy_to_client_enabled_tag 9
#define meshtastic_ModuleConfig_NeighborInfoConfig_enabled_tag 1
#define meshtastic_ModuleConfig_NeighborInfoConfig_update_interval_tag 2
#define meshtastic_ModuleConfig_DetectionSensorConfig_enabled_tag 1
#define meshtastic_ModuleConfig_DetectionSensorConfig_minimum_broadcast_secs_tag 2
#define meshtastic_ModuleConfig_DetectionSensorConfig_state_broadcast_secs_tag 3
#define meshtastic_ModuleConfig_DetectionSensorConfig_send_bell_tag 4
#define meshtastic_ModuleConfig_DetectionSensorConfig_name_tag 5
#define meshtastic_ModuleConfig_DetectionSensorConfig_monitor_pin_tag 6
#define meshtastic_ModuleConfig_DetectionSensorConfig_detection_triggered_high_tag 7
#define meshtastic_ModuleConfig_DetectionSensorConfig_use_pullup_tag 8
#define meshtastic_ModuleConfig_AudioConfig_codec2_enabled_tag 1
#define meshtastic_ModuleConfig_AudioConfig_ptt_pin_tag 2
#define meshtastic_ModuleConfig_AudioConfig_bitrate_tag 3
@@ -461,6 +514,7 @@ extern "C" {
#define meshtastic_ModuleConfig_ExternalNotificationConfig_alert_bell_vibra_tag 12
#define meshtastic_ModuleConfig_ExternalNotificationConfig_alert_bell_buzzer_tag 13
#define meshtastic_ModuleConfig_ExternalNotificationConfig_nag_timeout_tag 14
#define meshtastic_ModuleConfig_ExternalNotificationConfig_use_i2s_as_buzzer_tag 15
#define meshtastic_ModuleConfig_StoreForwardConfig_enabled_tag 1
#define meshtastic_ModuleConfig_StoreForwardConfig_heartbeat_tag 2
#define meshtastic_ModuleConfig_StoreForwardConfig_records_tag 3
@@ -476,6 +530,9 @@ extern "C" {
#define meshtastic_ModuleConfig_TelemetryConfig_environment_display_fahrenheit_tag 5
#define meshtastic_ModuleConfig_TelemetryConfig_air_quality_enabled_tag 6
#define meshtastic_ModuleConfig_TelemetryConfig_air_quality_interval_tag 7
#define meshtastic_ModuleConfig_TelemetryConfig_power_measurement_enabled_tag 8
#define meshtastic_ModuleConfig_TelemetryConfig_power_update_interval_tag 9
#define meshtastic_ModuleConfig_TelemetryConfig_power_screen_enabled_tag 10
#define meshtastic_ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3
@@ -509,6 +566,7 @@ extern "C" {
#define meshtastic_ModuleConfig_remote_hardware_tag 9
#define meshtastic_ModuleConfig_neighbor_info_tag 10
#define meshtastic_ModuleConfig_ambient_lighting_tag 11
#define meshtastic_ModuleConfig_detection_sensor_tag 12
/* Struct field encoding specification for nanopb */
#define meshtastic_ModuleConfig_FIELDLIST(X, a) \
@@ -522,7 +580,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,canned_message,payload_varia
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,audio,payload_variant.audio), 8) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_variant.remote_hardware), 9) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11)
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,detection_sensor,payload_variant.detection_sensor), 12)
#define meshtastic_ModuleConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_DEFAULT NULL
#define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
@@ -536,6 +595,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_var
#define meshtastic_ModuleConfig_payload_variant_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig
#define meshtastic_ModuleConfig_payload_variant_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig
#define meshtastic_ModuleConfig_payload_variant_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
#define meshtastic_ModuleConfig_payload_variant_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
#define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
@@ -564,6 +624,18 @@ X(a, STATIC, SINGULAR, UINT32, update_interval, 2)
#define meshtastic_ModuleConfig_NeighborInfoConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_NeighborInfoConfig_DEFAULT NULL
#define meshtastic_ModuleConfig_DetectionSensorConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
X(a, STATIC, SINGULAR, UINT32, minimum_broadcast_secs, 2) \
X(a, STATIC, SINGULAR, UINT32, state_broadcast_secs, 3) \
X(a, STATIC, SINGULAR, BOOL, send_bell, 4) \
X(a, STATIC, SINGULAR, STRING, name, 5) \
X(a, STATIC, SINGULAR, UINT32, monitor_pin, 6) \
X(a, STATIC, SINGULAR, BOOL, detection_triggered_high, 7) \
X(a, STATIC, SINGULAR, BOOL, use_pullup, 8)
#define meshtastic_ModuleConfig_DetectionSensorConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_DetectionSensorConfig_DEFAULT NULL
#define meshtastic_ModuleConfig_AudioConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, codec2_enabled, 1) \
X(a, STATIC, SINGULAR, UINT32, ptt_pin, 2) \
@@ -601,7 +673,8 @@ X(a, STATIC, SINGULAR, BOOL, alert_message_vibra, 10) \
X(a, STATIC, SINGULAR, BOOL, alert_message_buzzer, 11) \
X(a, STATIC, SINGULAR, BOOL, alert_bell_vibra, 12) \
X(a, STATIC, SINGULAR, BOOL, alert_bell_buzzer, 13) \
X(a, STATIC, SINGULAR, UINT32, nag_timeout, 14)
X(a, STATIC, SINGULAR, UINT32, nag_timeout, 14) \
X(a, STATIC, SINGULAR, BOOL, use_i2s_as_buzzer, 15)
#define meshtastic_ModuleConfig_ExternalNotificationConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_ExternalNotificationConfig_DEFAULT NULL
@@ -628,7 +701,10 @@ X(a, STATIC, SINGULAR, BOOL, environment_measurement_enabled, 3) \
X(a, STATIC, SINGULAR, BOOL, environment_screen_enabled, 4) \
X(a, STATIC, SINGULAR, BOOL, environment_display_fahrenheit, 5) \
X(a, STATIC, SINGULAR, BOOL, air_quality_enabled, 6) \
X(a, STATIC, SINGULAR, UINT32, air_quality_interval, 7)
X(a, STATIC, SINGULAR, UINT32, air_quality_interval, 7) \
X(a, STATIC, SINGULAR, BOOL, power_measurement_enabled, 8) \
X(a, STATIC, SINGULAR, UINT32, power_update_interval, 9) \
X(a, STATIC, SINGULAR, BOOL, power_screen_enabled, 10)
#define meshtastic_ModuleConfig_TelemetryConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_TelemetryConfig_DEFAULT NULL
@@ -667,6 +743,7 @@ extern const pb_msgdesc_t meshtastic_ModuleConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_MQTTConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_RemoteHardwareConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_NeighborInfoConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_DetectionSensorConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_AudioConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_SerialConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_ExternalNotificationConfig_msg;
@@ -682,6 +759,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
#define meshtastic_ModuleConfig_MQTTConfig_fields &meshtastic_ModuleConfig_MQTTConfig_msg
#define meshtastic_ModuleConfig_RemoteHardwareConfig_fields &meshtastic_ModuleConfig_RemoteHardwareConfig_msg
#define meshtastic_ModuleConfig_NeighborInfoConfig_fields &meshtastic_ModuleConfig_NeighborInfoConfig_msg
#define meshtastic_ModuleConfig_DetectionSensorConfig_fields &meshtastic_ModuleConfig_DetectionSensorConfig_msg
#define meshtastic_ModuleConfig_AudioConfig_fields &meshtastic_ModuleConfig_AudioConfig_msg
#define meshtastic_ModuleConfig_SerialConfig_fields &meshtastic_ModuleConfig_SerialConfig_msg
#define meshtastic_ModuleConfig_ExternalNotificationConfig_fields &meshtastic_ModuleConfig_ExternalNotificationConfig_msg
@@ -696,14 +774,15 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
#define meshtastic_ModuleConfig_AmbientLightingConfig_size 14
#define meshtastic_ModuleConfig_AudioConfig_size 19
#define meshtastic_ModuleConfig_CannedMessageConfig_size 49
#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 40
#define meshtastic_ModuleConfig_DetectionSensorConfig_size 44
#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 42
#define meshtastic_ModuleConfig_MQTTConfig_size 222
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 8
#define meshtastic_ModuleConfig_RangeTestConfig_size 10
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
#define meshtastic_ModuleConfig_SerialConfig_size 28
#define meshtastic_ModuleConfig_StoreForwardConfig_size 22
#define meshtastic_ModuleConfig_TelemetryConfig_size 26
#define meshtastic_ModuleConfig_TelemetryConfig_size 36
#define meshtastic_ModuleConfig_size 225
#define meshtastic_RemoteHardwarePin_size 21

View File

@@ -69,6 +69,9 @@ typedef enum _meshtastic_PortNum {
NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate.
This marker comes from the 'moduleConfig.audio.bitrate' enum minus one. */
meshtastic_PortNum_AUDIO_APP = 9,
/* Same as Text Message but originating from Detection Sensor Module.
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 */
meshtastic_PortNum_DETECTION_SENSOR_APP = 10,
/* Provides a 'ping' service that replies to any packet it receives.
Also serves as a small example module.
ENCODING: ASCII Plaintext */
@@ -88,7 +91,8 @@ typedef enum _meshtastic_PortNum {
ENCODING: Protobuf */
meshtastic_PortNum_STORE_FORWARD_APP = 65,
/* Optional port for messages for the range test module.
ENCODING: ASCII Plaintext */
ENCODING: ASCII Plaintext
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 */
meshtastic_PortNum_RANGE_TEST_APP = 66,
/* Provides a format to send and receive telemetry data from the Meshtastic network.
Maintained by Charles Crossan (crossan007) : crossan007@gmail.com

View File

@@ -12,6 +12,9 @@ PB_BIND(meshtastic_DeviceMetrics, meshtastic_DeviceMetrics, AUTO)
PB_BIND(meshtastic_EnvironmentMetrics, meshtastic_EnvironmentMetrics, AUTO)
PB_BIND(meshtastic_PowerMetrics, meshtastic_PowerMetrics, AUTO)
PB_BIND(meshtastic_AirQualityMetrics, meshtastic_AirQualityMetrics, AUTO)

View File

@@ -39,7 +39,9 @@ typedef enum _meshtastic_TelemetrySensorType {
/* High accuracy temperature and humidity */
meshtastic_TelemetrySensorType_SHT31 = 12,
/* PM2.5 air quality sensor */
meshtastic_TelemetrySensorType_PMSA003I = 13
meshtastic_TelemetrySensorType_PMSA003I = 13,
/* INA3221 3 Channel Voltage / Current Sensor */
meshtastic_TelemetrySensorType_INA3221 = 14
} meshtastic_TelemetrySensorType;
/* Struct definitions */
@@ -65,12 +67,28 @@ typedef struct _meshtastic_EnvironmentMetrics {
float barometric_pressure;
/* Gas resistance in MOhm measured */
float gas_resistance;
/* Voltage measured */
/* Voltage measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) */
float voltage;
/* Current measured */
/* Current measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) */
float current;
} meshtastic_EnvironmentMetrics;
/* Power Metrics (voltage / current / etc) */
typedef struct _meshtastic_PowerMetrics {
/* Voltage (Ch1) */
float ch1_voltage;
/* Current (Ch1) */
float ch1_current;
/* Voltage (Ch2) */
float ch2_voltage;
/* Current (Ch2) */
float ch2_current;
/* Voltage (Ch3) */
float ch3_voltage;
/* Current (Ch3) */
float ch3_current;
} meshtastic_PowerMetrics;
/* Air quality metrics */
typedef struct _meshtastic_AirQualityMetrics {
/* Concentration Units Standard PM1.0 */
@@ -101,11 +119,7 @@ typedef struct _meshtastic_AirQualityMetrics {
/* Types of Measurements the telemetry module is equipped to handle */
typedef struct _meshtastic_Telemetry {
/* This is usually not sent over the mesh (to save space), but it is sent
from the phone so that the local device can set its RTC If it is sent over
the mesh (because there are devices on the mesh without GPS), it will only
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
seconds since 1970 */
/* Seconds since 1970 - or 0 for unknown/unset */
uint32_t time;
pb_size_t which_variant;
union {
@@ -115,6 +129,8 @@ typedef struct _meshtastic_Telemetry {
meshtastic_EnvironmentMetrics environment_metrics;
/* Air quality metrics */
meshtastic_AirQualityMetrics air_quality_metrics;
/* Power Metrics */
meshtastic_PowerMetrics power_metrics;
} variant;
} meshtastic_Telemetry;
@@ -125,8 +141,9 @@ extern "C" {
/* Helper constants for enums */
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_PMSA003I
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_PMSA003I+1))
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_INA3221
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_INA3221+1))
@@ -136,10 +153,12 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0}
#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0}
#define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0}
#define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}}
#define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0}
#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0}
#define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0}
#define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}}
@@ -154,6 +173,12 @@ extern "C" {
#define meshtastic_EnvironmentMetrics_gas_resistance_tag 4
#define meshtastic_EnvironmentMetrics_voltage_tag 5
#define meshtastic_EnvironmentMetrics_current_tag 6
#define meshtastic_PowerMetrics_ch1_voltage_tag 1
#define meshtastic_PowerMetrics_ch1_current_tag 2
#define meshtastic_PowerMetrics_ch2_voltage_tag 3
#define meshtastic_PowerMetrics_ch2_current_tag 4
#define meshtastic_PowerMetrics_ch3_voltage_tag 5
#define meshtastic_PowerMetrics_ch3_current_tag 6
#define meshtastic_AirQualityMetrics_pm10_standard_tag 1
#define meshtastic_AirQualityMetrics_pm25_standard_tag 2
#define meshtastic_AirQualityMetrics_pm100_standard_tag 3
@@ -170,6 +195,7 @@ extern "C" {
#define meshtastic_Telemetry_device_metrics_tag 2
#define meshtastic_Telemetry_environment_metrics_tag 3
#define meshtastic_Telemetry_air_quality_metrics_tag 4
#define meshtastic_Telemetry_power_metrics_tag 5
/* Struct field encoding specification for nanopb */
#define meshtastic_DeviceMetrics_FIELDLIST(X, a) \
@@ -190,6 +216,16 @@ X(a, STATIC, SINGULAR, FLOAT, current, 6)
#define meshtastic_EnvironmentMetrics_CALLBACK NULL
#define meshtastic_EnvironmentMetrics_DEFAULT NULL
#define meshtastic_PowerMetrics_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, FLOAT, ch1_voltage, 1) \
X(a, STATIC, SINGULAR, FLOAT, ch1_current, 2) \
X(a, STATIC, SINGULAR, FLOAT, ch2_voltage, 3) \
X(a, STATIC, SINGULAR, FLOAT, ch2_current, 4) \
X(a, STATIC, SINGULAR, FLOAT, ch3_voltage, 5) \
X(a, STATIC, SINGULAR, FLOAT, ch3_current, 6)
#define meshtastic_PowerMetrics_CALLBACK NULL
#define meshtastic_PowerMetrics_DEFAULT NULL
#define meshtastic_AirQualityMetrics_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, pm10_standard, 1) \
X(a, STATIC, SINGULAR, UINT32, pm25_standard, 2) \
@@ -210,21 +246,25 @@ X(a, STATIC, SINGULAR, UINT32, particles_100um, 12)
X(a, STATIC, SINGULAR, FIXED32, time, 1) \
X(a, STATIC, ONEOF, MESSAGE, (variant,device_metrics,variant.device_metrics), 2) \
X(a, STATIC, ONEOF, MESSAGE, (variant,environment_metrics,variant.environment_metrics), 3) \
X(a, STATIC, ONEOF, MESSAGE, (variant,air_quality_metrics,variant.air_quality_metrics), 4)
X(a, STATIC, ONEOF, MESSAGE, (variant,air_quality_metrics,variant.air_quality_metrics), 4) \
X(a, STATIC, ONEOF, MESSAGE, (variant,power_metrics,variant.power_metrics), 5)
#define meshtastic_Telemetry_CALLBACK NULL
#define meshtastic_Telemetry_DEFAULT NULL
#define meshtastic_Telemetry_variant_device_metrics_MSGTYPE meshtastic_DeviceMetrics
#define meshtastic_Telemetry_variant_environment_metrics_MSGTYPE meshtastic_EnvironmentMetrics
#define meshtastic_Telemetry_variant_air_quality_metrics_MSGTYPE meshtastic_AirQualityMetrics
#define meshtastic_Telemetry_variant_power_metrics_MSGTYPE meshtastic_PowerMetrics
extern const pb_msgdesc_t meshtastic_DeviceMetrics_msg;
extern const pb_msgdesc_t meshtastic_EnvironmentMetrics_msg;
extern const pb_msgdesc_t meshtastic_PowerMetrics_msg;
extern const pb_msgdesc_t meshtastic_AirQualityMetrics_msg;
extern const pb_msgdesc_t meshtastic_Telemetry_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_DeviceMetrics_fields &meshtastic_DeviceMetrics_msg
#define meshtastic_EnvironmentMetrics_fields &meshtastic_EnvironmentMetrics_msg
#define meshtastic_PowerMetrics_fields &meshtastic_PowerMetrics_msg
#define meshtastic_AirQualityMetrics_fields &meshtastic_AirQualityMetrics_msg
#define meshtastic_Telemetry_fields &meshtastic_Telemetry_msg
@@ -232,6 +272,7 @@ extern const pb_msgdesc_t meshtastic_Telemetry_msg;
#define meshtastic_AirQualityMetrics_size 72
#define meshtastic_DeviceMetrics_size 21
#define meshtastic_EnvironmentMetrics_size 30
#define meshtastic_PowerMetrics_size 30
#define meshtastic_Telemetry_size 79
#ifdef __cplusplus

View File

@@ -144,8 +144,8 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res)
/*
For documentation, see:
https://meshtastic.org/docs/developers/device/http-api
https://meshtastic.org/docs/developers/device/device-api
https://meshtastic.org/docs/development/device/http-api
https://meshtastic.org/docs/development/device/client-api
*/
// Get access to the parameters
@@ -194,8 +194,8 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
/*
For documentation, see:
https://meshtastic.org/docs/developers/device/http-api
https://meshtastic.org/docs/developers/device/device-api
https://meshtastic.org/docs/development/device/http-api
https://meshtastic.org/docs/development/device/client-api
*/
res->setHeader("Content-Type", "application/x-protobuf");

View File

@@ -25,7 +25,7 @@ bool pb_decode_from_bytes(const uint8_t *srcbuf, size_t srcbufsize, const pb_msg
{
pb_istream_t stream = pb_istream_from_buffer(srcbuf, srcbufsize);
if (!pb_decode(&stream, fields, dest_struct)) {
LOG_ERROR("Can't decode protobuf reason='%s', pb_msgdesc 0x%p\n", PB_GET_ERROR(&stream), fields);
LOG_ERROR("Can't decode protobuf reason='%s', pb_msgdesc %p\n", PB_GET_ERROR(&stream), fields);
return false;
} else {
return true;

58
src/meshUtils.cpp Normal file
View File

@@ -0,0 +1,58 @@
#include "meshUtils.h"
#include <string.h>
/*
* Find the first occurrence of find in s, where the search is limited to the
* first slen characters of s.
* -
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
char *strnstr(const char *s, const char *find, size_t slen)
{
char c, sc;
size_t len;
if ((c = *find++) != '\0') {
len = strlen(find);
do {
do {
if (slen-- < 1 || (sc = *s++) == '\0')
return (NULL);
} while (sc != c);
if (len > slen)
return (NULL);
} while (strncmp(s, find, len) != 0);
s--;
}
return ((char *)s);
}

View File

@@ -4,4 +4,9 @@
template <class T> constexpr const T &clamp(const T &v, const T &lo, const T &hi)
{
return (v < lo) ? lo : (hi < v) ? hi : v;
}
}
#if (defined(ARCH_PORTDUINO) && !defined(STRNSTR))
#define STRNSTR
char *strnstr(const char *s, const char *find, size_t slen);
#endif

View File

@@ -182,6 +182,12 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
}
break;
}
case meshtastic_AdminMessage_remove_by_nodenum_tag: {
LOG_INFO("Client is receiving a remove_nodenum command.\n");
nodeDB.removeNodeByNum(r->remove_by_nodenum);
reboot(DEFAULT_REBOOT_SECONDS);
break;
}
#ifdef ARCH_PORTDUINO
case meshtastic_AdminMessage_exit_simulator_tag:
LOG_INFO("Exiting simulator\n");
@@ -373,6 +379,16 @@ void AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
moduleConfig.has_neighbor_info = true;
moduleConfig.neighbor_info = c.payload_variant.neighbor_info;
break;
case meshtastic_ModuleConfig_detection_sensor_tag:
LOG_INFO("Setting module config: Detection Sensor\n");
moduleConfig.has_detection_sensor = true;
moduleConfig.detection_sensor = c.payload_variant.detection_sensor;
break;
case meshtastic_ModuleConfig_ambient_lighting_tag:
LOG_INFO("Setting module config: Ambient Lighting\n");
moduleConfig.has_ambient_lighting = true;
moduleConfig.ambient_lighting = c.payload_variant.ambient_lighting;
break;
}
saveChanges(SEGMENT_MODULECONFIG);
@@ -513,6 +529,16 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag;
res.get_module_config_response.payload_variant.neighbor_info = moduleConfig.neighbor_info;
break;
case meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG:
LOG_INFO("Getting module config: Detection Sensor\n");
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
res.get_module_config_response.payload_variant.detection_sensor = moduleConfig.detection_sensor;
break;
case meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG:
LOG_INFO("Getting module config: Ambient Lighting\n");
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag;
res.get_module_config_response.payload_variant.ambient_lighting = moduleConfig.ambient_lighting;
break;
}
// NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior.
@@ -666,7 +692,7 @@ void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p)
channels.onConfigChanged();
service.reloadOwner(false);
service.reloadConfig(SEGMENT_CONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
saveChanges(SEGMENT_CONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
}
AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_APP, &meshtastic_AdminMessage_msg)

View File

@@ -63,10 +63,10 @@ CannedMessageModule *cannedMessageModule;
CannedMessageModule::CannedMessageModule()
: SinglePortModule("canned", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("CannedMessageModule")
{
if (moduleConfig.canned_message.enabled) {
if (moduleConfig.canned_message.enabled || CANNED_MESSAGE_MODULE_ENABLE) {
this->loadProtoForModule();
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address != CARDKB_ADDR) &&
(cardkb_found.address != TDECK_KB_ADDR) && !INPUTBROKER_MATRIX_TYPE) {
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address == 0x00) && !INPUTBROKER_MATRIX_TYPE &&
!CANNED_MESSAGE_MODULE_ENABLE) {
LOG_INFO("CannedMessageModule: No messages are configured. Module is disabled\n");
this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED;
disable();
@@ -171,7 +171,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) {
// LOG_DEBUG("Canned message event (%x)\n", event->kbchar);
// tweak for left/right events generated via trackball/touch with empty kbchar
// tweak for left/right events generated via trackball/touch with empty kbchar
if (!event->kbchar) {
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
this->payload = 0xb4;
@@ -195,6 +195,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
}
// pass the pressed key
// LOG_DEBUG("Canned message ANYKEY (%x)\n", event->kbchar);
this->payload = event->kbchar;
this->lastTouchMillis = millis();
validEvent = true;
@@ -237,8 +238,8 @@ void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantR
int32_t CannedMessageModule::runOnce()
{
if ((!moduleConfig.canned_message.enabled) || (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) ||
(this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
if (((!moduleConfig.canned_message.enabled) && !CANNED_MESSAGE_MODULE_ENABLE) ||
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) || (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
return INT32_MAX;
}
// LOG_DEBUG("Check status\n");
@@ -454,7 +455,7 @@ const char *CannedMessageModule::getNodeName(NodeNum node)
bool CannedMessageModule::shouldDraw()
{
if (!moduleConfig.canned_message.enabled) {
if (!moduleConfig.canned_message.enabled && !CANNED_MESSAGE_MODULE_ENABLE) {
return false;
}
return (currentMessageIndex != -1) || (this->runState != CANNED_MESSAGE_RUN_STATE_INACTIVE);
@@ -649,4 +650,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
return result;
}
#endif
#endif

View File

@@ -20,6 +20,10 @@ enum cannedMessageModuleRunState {
*/
#define CANNED_MESSAGE_MODULE_MESSAGES_SIZE 800
#ifndef CANNED_MESSAGE_MODULE_ENABLE
#define CANNED_MESSAGE_MODULE_ENABLE 0
#endif
class CannedMessageModule : public SinglePortModule, public Observable<const UIFrameEvent *>, private concurrency::OSThread
{
CallbackObserver<CannedMessageModule, const InputEvent *> inputObserver =

View File

@@ -0,0 +1,108 @@
#include "DetectionSensorModule.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "main.h"
DetectionSensorModule *detectionSensorModule;
#define GPIO_POLLING_INTERVAL 100
#define DELAYED_INTERVAL 1000
int32_t DetectionSensorModule::runOnce()
{
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
// moduleConfig.detection_sensor.enabled = true;
// moduleConfig.detection_sensor.monitor_pin = 10; // WisBlock PIR IO6
// moduleConfig.detection_sensor.monitor_pin = 21; // WisBlock RAK12013 Radar IO6
// moduleConfig.detection_sensor.minimum_broadcast_secs = 30;
// moduleConfig.detection_sensor.state_broadcast_secs = 120;
// moduleConfig.detection_sensor.detection_triggered_high = true;
// strcpy(moduleConfig.detection_sensor.name, "Motion");
if (moduleConfig.detection_sensor.enabled == false)
return disable();
if (firstTime) {
#ifdef DETECTION_SENSOR_EN
pinMode(DETECTION_SENSOR_EN, OUTPUT);
digitalWrite(DETECTION_SENSOR_EN, HIGH);
#endif
// This is the first time the OSThread library has called this function, so do some setup
firstTime = false;
if (moduleConfig.detection_sensor.monitor_pin > 0) {
pinMode(moduleConfig.detection_sensor.monitor_pin, moduleConfig.detection_sensor.use_pullup ? INPUT_PULLUP : INPUT);
} else {
LOG_WARN("Detection Sensor Module: Set to enabled but no monitor pin is set. Disabling module...\n");
return disable();
}
LOG_INFO("Detection Sensor Module: Initializing\n");
return DELAYED_INTERVAL;
}
// LOG_DEBUG("Detection Sensor Module: Current pin state: %i\n", digitalRead(moduleConfig.detection_sensor.monitor_pin));
if ((millis() - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs) &&
hasDetectionEvent()) {
sendDetectionMessage();
return DELAYED_INTERVAL;
}
// Even if we haven't detected an event, broadcast our current state to the mesh on the scheduled interval as a sort
// of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state
// change detections.
else if (moduleConfig.detection_sensor.state_broadcast_secs > 0 &&
(millis() - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs)) {
sendCurrentStateMessage();
return DELAYED_INTERVAL;
}
return GPIO_POLLING_INTERVAL;
}
void DetectionSensorModule::sendDetectionMessage()
{
LOG_DEBUG("Detected event observed. Sending message\n");
char *message = new char[40];
sprintf(message, "%s detected", moduleConfig.detection_sensor.name);
meshtastic_MeshPacket *p = allocDataPacket();
p->want_ack = false;
p->decoded.payload.size = strlen(message);
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
if (moduleConfig.detection_sensor.send_bell && p->decoded.payload.size < meshtastic_Constants_DATA_PAYLOAD_LEN) {
p->decoded.payload.bytes[p->decoded.payload.size] = 7; // Bell character
p->decoded.payload.bytes[p->decoded.payload.size + 1] = '\0'; // Bell character
p->decoded.payload.size++;
}
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
lastSentToMesh = millis();
service.sendToMesh(p);
delete[] message;
}
void DetectionSensorModule::sendCurrentStateMessage()
{
char *message = new char[40];
sprintf(message, "%s state: %i", moduleConfig.detection_sensor.name, hasDetectionEvent());
meshtastic_MeshPacket *p = allocDataPacket();
p->want_ack = false;
p->decoded.payload.size = strlen(message);
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
lastSentToMesh = millis();
service.sendToMesh(p);
delete[] message;
}
bool DetectionSensorModule::hasDetectionEvent()
{
bool currentState = digitalRead(moduleConfig.detection_sensor.monitor_pin);
// LOG_DEBUG("Detection Sensor Module: Current state: %i\n", currentState);
return moduleConfig.detection_sensor.detection_triggered_high ? currentState : !currentState;
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include "SinglePortModule.h"
class DetectionSensorModule : public SinglePortModule, private concurrency::OSThread
{
public:
DetectionSensorModule()
: SinglePortModule("detection", meshtastic_PortNum_DETECTION_SENSOR_APP), OSThread("DetectionSensorModule")
{
}
protected:
virtual int32_t runOnce() override;
private:
bool firstTime = true;
uint32_t lastSentToMesh = 0;
void sendDetectionMessage();
void sendCurrentStateMessage();
bool hasDetectionEvent();
};
extern DetectionSensorModule *detectionSensorModule;

View File

@@ -8,7 +8,7 @@
* handle the module's behavior.
*
* Documentation:
* https://meshtastic.org/docs/settings/moduleconfig/external-notification
* https://meshtastic.org/docs/configuration/module/external-notification
*
* @author Jm Casler & Meshtastic Team
* @date [Insert Date]
@@ -27,11 +27,14 @@
#ifdef HAS_NCP5623
#include <graphics/RAKled.h>
NCP5623 rgb;
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 0;
uint8_t colorState = 1;
uint8_t brightnessIndex = 0;
uint8_t brightnessValues[] = {0, 10, 20, 30, 50, 90, 160, 170}; // blue gets multiplied by 1.5
bool ascending = true;
#endif
#ifndef PIN_BUZZER
@@ -40,7 +43,7 @@ uint8_t blue = 0;
/*
Documentation:
https://meshtastic.org/docs/settings/moduleconfig/external-notification
https://meshtastic.org/docs/configuration/module/external-notification
*/
// Default configurations
@@ -101,11 +104,26 @@ int32_t ExternalNotificationModule::runOnce()
}
#ifdef HAS_NCP5623
if (rgb_found.type == ScanI2C::NCP5623) {
green = (green + 50) % 255;
red = abs(red - green) % 255;
blue = abs(blue / red) % 255;
red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7
green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7
blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7
rgb.setColor(red, green, blue);
if (ascending) { // fade in
brightnessIndex++;
if (brightnessIndex == (sizeof(brightnessValues) - 1)) {
ascending = false;
}
} else {
brightnessIndex--; // fade out
}
if (brightnessIndex == 0) {
ascending = true;
colorState++; // next color
if (colorState > 7) {
colorState = 1;
}
}
}
#endif
@@ -128,6 +146,11 @@ int32_t ExternalNotificationModule::runOnce()
}
}
bool ExternalNotificationModule::wantPacket(const meshtastic_MeshPacket *p)
{
return MeshService::isTextPayload(p);
}
/**
* Sets the external notification on for the specified index.
*
@@ -212,8 +235,8 @@ void ExternalNotificationModule::stopNow()
}
ExternalNotificationModule::ExternalNotificationModule()
: SinglePortModule("ExternalNotificationModule", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread(
"ExternalNotificationModule")
: SinglePortModule("ExternalNotificationModule", meshtastic_PortNum_TEXT_MESSAGE_APP),
concurrency::OSThread("ExternalNotificationModule")
{
/*
Uncomment the preferences below if you want to use the module

View File

@@ -52,6 +52,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
virtual int32_t runOnce() override;
virtual bool wantPacket(const meshtastic_MeshPacket *p) override;
bool isNagging = false;
virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
@@ -59,4 +61,4 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
meshtastic_AdminMessage *response) override;
};
extern ExternalNotificationModule *externalNotificationModule;
extern ExternalNotificationModule *externalNotificationModule;

View File

@@ -7,6 +7,7 @@
#include "input/kbMatrixImpl.h"
#include "modules/AdminModule.h"
#include "modules/CannedMessageModule.h"
#include "modules/DetectionSensorModule.h"
#include "modules/NeighborInfoModule.h"
#include "modules/NodeInfoModule.h"
#include "modules/PositionModule.h"
@@ -23,6 +24,9 @@
#include "modules/Telemetry/AirQualityTelemetry.h"
#include "modules/Telemetry/EnvironmentTelemetry.h"
#endif
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
#include "modules/Telemetry/PowerTelemetry.h"
#endif
#ifdef ARCH_ESP32
#include "modules/esp32/AudioModule.h"
#include "modules/esp32/StoreForwardModule.h"
@@ -30,7 +34,7 @@
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
#include "modules/ExternalNotificationModule.h"
#include "modules/RangeTestModule.h"
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(CONFIG_IDF_TARGET_ESP32S2)
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2)
#include "modules/SerialModule.h"
#endif
#endif
@@ -50,6 +54,7 @@ void setupModules()
textMessageModule = new TextMessageModule();
traceRouteModule = new TraceRouteModule();
neighborInfoModule = new NeighborInfoModule();
detectionSensorModule = new DetectionSensorModule();
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
// to a global variable.
@@ -58,9 +63,15 @@ void setupModules()
new ReplyModule();
#if HAS_BUTTON
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
rotaryEncoderInterruptImpl1->init();
if (!rotaryEncoderInterruptImpl1->init()) {
delete rotaryEncoderInterruptImpl1;
rotaryEncoderInterruptImpl1 = nullptr;
}
upDownInterruptImpl1 = new UpDownInterruptImpl1();
upDownInterruptImpl1->init();
if (!upDownInterruptImpl1->init()) {
delete upDownInterruptImpl1;
upDownInterruptImpl1 = nullptr;
}
cardKbI2cImpl = new CardKbI2cImpl();
cardKbI2cImpl->init();
#ifdef INPUTBROKER_MATRIX_TYPE
@@ -80,11 +91,15 @@ void setupModules()
#endif
#if HAS_SENSOR
new EnvironmentTelemetryModule();
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I] > 0) {
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
new AirQualityTelemetryModule();
}
#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
new PowerTelemetryModule();
#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
!defined(CONFIG_IDF_TARGET_ESP32C3)
new SerialModule();
#endif
#ifdef ARCH_ESP32

View File

@@ -15,12 +15,12 @@ NOTE: For debugging only
*/
void NeighborInfoModule::printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np)
{
LOG_DEBUG("%s NEIGHBORINFO PACKET from Node %d to Node %d (last sent by %d)\n", header, np->node_id, nodeDB.getNodeNum(),
np->last_sent_by_id);
LOG_DEBUG("%s NEIGHBORINFO PACKET from Node 0x%x to Node 0x%x (last sent by 0x%x)\n", header, np->node_id,
nodeDB.getNodeNum(), np->last_sent_by_id);
LOG_DEBUG("----------------\n");
LOG_DEBUG("Packet contains %d neighbors\n", np->neighbors_count);
for (int i = 0; i < np->neighbors_count; i++) {
LOG_DEBUG("Neighbor %d: node_id=%d, snr=%.2f\n", i, np->neighbors[i].node_id, np->neighbors[i].snr);
LOG_DEBUG("Neighbor %d: node_id=0x%x, snr=%.2f\n", i, np->neighbors[i].node_id, np->neighbors[i].snr);
}
LOG_DEBUG("----------------\n");
}
@@ -31,12 +31,12 @@ NOTE: for debugging only
void NeighborInfoModule::printNodeDBNodes(const char *header)
{
int num_nodes = nodeDB.getNumMeshNodes();
LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum());
LOG_DEBUG("%s NODEDB SELECTION from Node 0x%x:\n", header, nodeDB.getNodeNum());
LOG_DEBUG("----------------\n");
LOG_DEBUG("DB contains %d nodes\n", num_nodes);
for (int i = 0; i < num_nodes; i++) {
const meshtastic_NodeInfoLite *dbEntry = nodeDB.getMeshNodeByIndex(i);
LOG_DEBUG(" Node %d: node_id=%d, snr=%.2f\n", i, dbEntry->num, dbEntry->snr);
LOG_DEBUG(" Node %d: node_id=0x%x, snr=%.2f\n", i, dbEntry->num, dbEntry->snr);
}
LOG_DEBUG("----------------\n");
}
@@ -48,12 +48,12 @@ NOTE: for debugging only
void NeighborInfoModule::printNodeDBNeighbors(const char *header)
{
int num_neighbors = getNumNeighbors();
LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum());
LOG_DEBUG("%s NODEDB SELECTION from Node 0x%x:\n", header, nodeDB.getNodeNum());
LOG_DEBUG("----------------\n");
LOG_DEBUG("DB contains %d neighbors\n", num_neighbors);
for (int i = 0; i < num_neighbors; i++) {
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
LOG_DEBUG(" Node %d: node_id=%d, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
LOG_DEBUG(" Node %d: node_id=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
}
LOG_DEBUG("----------------\n");
}
@@ -66,7 +66,7 @@ NOTE: For debugging only
void NeighborInfoModule::printNodeDBSelection(const char *header, const meshtastic_NeighborInfo *np)
{
int num_neighbors = getNumNeighbors();
LOG_DEBUG("%s NODEDB SELECTION from Node %d:\n", header, nodeDB.getNodeNum());
LOG_DEBUG("%s NODEDB SELECTION from Node 0x%x:\n", header, nodeDB.getNodeNum());
LOG_DEBUG("----------------\n");
LOG_DEBUG("Selected %d neighbors of %d DB neighbors\n", np->neighbors_count, num_neighbors);
for (int i = 0; i < num_neighbors; i++) {
@@ -78,9 +78,9 @@ void NeighborInfoModule::printNodeDBSelection(const char *header, const meshtast
}
}
if (!chosen) {
LOG_DEBUG(" Node %d: neighbor=%d, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
LOG_DEBUG(" Node %d: neighbor=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
} else {
LOG_DEBUG("---> Node %d: neighbor=%d, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
LOG_DEBUG("---> Node %d: neighbor=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
}
}
LOG_DEBUG("----------------\n");
@@ -88,9 +88,9 @@ void NeighborInfoModule::printNodeDBSelection(const char *header, const meshtast
/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */
NeighborInfoModule::NeighborInfoModule()
: neighbors(neighborState.neighbors), numNeighbors(&neighborState.neighbors_count),
ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg), concurrency::OSThread(
"NeighborInfoModule")
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
concurrency::OSThread("NeighborInfoModule"), neighbors(neighborState.neighbors),
numNeighbors(&neighborState.neighbors_count)
{
ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP;
@@ -103,16 +103,6 @@ NeighborInfoModule::NeighborInfoModule()
}
}
/*
Allocate a zeroed neighbor info packet
*/
meshtastic_NeighborInfo *NeighborInfoModule::allocateNeighborInfoPacket()
{
meshtastic_NeighborInfo *neighborInfo = (meshtastic_NeighborInfo *)malloc(sizeof(meshtastic_NeighborInfo));
memset(neighborInfo, 0, sizeof(meshtastic_NeighborInfo));
return neighborInfo;
}
/*
Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
Assumes that the neighborInfo packet has been allocated
@@ -120,7 +110,7 @@ Assumes that the neighborInfo packet has been allocated
*/
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
{
int my_node_id = nodeDB.getNodeNum();
uint my_node_id = nodeDB.getNodeNum();
neighborInfo->node_id = my_node_id;
neighborInfo->last_sent_by_id = my_node_id;
neighborInfo->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
@@ -184,14 +174,14 @@ size_t NeighborInfoModule::cleanUpNeighbors()
/* Send neighbor info to the mesh */
void NeighborInfoModule::sendNeighborInfo(NodeNum dest, bool wantReplies)
{
meshtastic_NeighborInfo *neighborInfo = allocateNeighborInfoPacket();
collectNeighborInfo(neighborInfo);
meshtastic_MeshPacket *p = allocDataProtobuf(*neighborInfo);
meshtastic_NeighborInfo neighborInfo = meshtastic_NeighborInfo_init_zero;
collectNeighborInfo(&neighborInfo);
meshtastic_MeshPacket *p = allocDataProtobuf(neighborInfo);
// send regardless of whether or not we have neighbors in our DB,
// because we want to get neighbors for the next cycle
p->to = dest;
p->decoded.want_response = wantReplies;
printNeighborInfo("SENDING", neighborInfo);
printNeighborInfo("SENDING", &neighborInfo);
service.sendToMesh(p, RX_SRC_LOCAL, true);
}
@@ -212,8 +202,10 @@ Pass it to an upper client; do not persist this data on the mesh
*/
bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
{
printNeighborInfo("RECEIVED", np);
updateNeighbors(mp, np);
if (enabled) {
printNeighborInfo("RECEIVED", np);
updateNeighbors(mp, np);
}
// Allow others to handle this packet
return false;
}
@@ -255,7 +247,7 @@ void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const
}
meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSender, NodeNum n,
uint32_t node_broadcast_interval_secs, int snr)
uint32_t node_broadcast_interval_secs, float snr)
{
// our node and the phone are the same node (not neighbors)
if (n == 0) {
@@ -277,7 +269,7 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen
}
// otherwise, allocate one and assign data to it
// TODO: max memory for the database should take neighbors into account, but currently doesn't
if (*numNeighbors < MAX_NUM_NODES) {
if (*numNeighbors < MAX_NUM_NEIGHBORS) {
(*numNeighbors)++;
}
meshtastic_Neighbor *new_nbr = &neighbors[((*numNeighbors) - 1)];

View File

@@ -49,7 +49,7 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
meshtastic_NeighborInfo *allocateNeighborInfoPacket();
// Find a neighbor in our DB, create an empty neighbor if missing
meshtastic_Neighbor *getOrCreateNeighbor(NodeNum originalSender, NodeNum n, uint32_t node_broadcast_interval_secs, int snr);
meshtastic_Neighbor *getOrCreateNeighbor(NodeNum originalSender, NodeNum n, uint32_t node_broadcast_interval_secs, float snr);
/*
* Send info on our node's neighbors into the mesh

View File

@@ -40,7 +40,9 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
meshtastic_MeshPacket *p = allocReply();
if (p) { // Check whether we didn't ignore it
p->to = dest;
p->decoded.want_response = wantReplies;
p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&
config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
wantReplies;
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
if (channel > 0) {
LOG_DEBUG("sending ourNodeInfo to channel %d\n", channel);

View File

@@ -1,4 +1,5 @@
#include "PositionModule.h"
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "RTC.h"
@@ -7,15 +8,34 @@
#include "airtime.h"
#include "configuration.h"
#include "gps/GeoCoord.h"
#include "sleep.h"
#include "target_specific.h"
PositionModule *positionModule;
PositionModule::PositionModule()
: ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg), concurrency::OSThread(
"PositionModule")
: ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg),
concurrency::OSThread("PositionModule")
{
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
if (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)
setIntervalFromNow(60 * 1000);
// Power saving trackers should clear their position on startup to avoid waking up and sending a stale position
if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER && config.power.is_power_saving) {
clearPosition();
}
}
void PositionModule::clearPosition()
{
LOG_DEBUG("Clearing position on startup for sleepy tracker (ー。ー) zzz\n");
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
node->position.latitude_i = 0;
node->position.longitude_i = 0;
node->position.altitude = 0;
node->position.time = 0;
nodeDB.setLocalPosition(meshtastic_Position_init_default);
}
bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Position *pptr)
@@ -27,18 +47,19 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER)
// to set fixed location, EUD-GPS location or just the time (see also issue #900)
bool isLocal = false;
if (nodeDB.getNodeNum() == getFrom(&mp)) {
LOG_DEBUG("Incoming update from MYSELF\n");
// LOG_DEBUG("Ignored an incoming update from MYSELF\n");
// return false;
isLocal = true;
nodeDB.setLocalPosition(p);
}
// Log packet size and list of fields
LOG_INFO("POSITION node=%08x l=%d %s%s%s%s%s%s%s%s%s%s%s%s%s\n", getFrom(&mp), mp.decoded.payload.size,
p.latitude_i ? "LAT " : "", p.longitude_i ? "LON " : "", p.altitude ? "MSL " : "", p.altitude_hae ? "HAE " : "",
p.altitude_geoidal_separation ? "GEO " : "", p.PDOP ? "PDOP " : "", p.HDOP ? "HDOP " : "", p.VDOP ? "VDOP " : "",
p.sats_in_view ? "SIV " : "", p.fix_quality ? "FXQ " : "", p.fix_type ? "FXT " : "", p.timestamp ? "PTS " : "",
p.time ? "TIME " : "");
// Log packet size and data fields
LOG_INFO("POSITION node=%08x l=%d latI=%d lonI=%d msl=%d hae=%d geo=%d pdop=%d hdop=%d vdop=%d siv=%d fxq=%d fxt=%d pts=%d "
"time=%d\n",
getFrom(&mp), mp.decoded.payload.size, p.latitude_i, p.longitude_i, p.altitude, p.altitude_hae,
p.altitude_geoidal_separation, p.PDOP, p.HDOP, p.VDOP, p.sats_in_view, p.fix_quality, p.fix_type, p.timestamp,
p.time);
if (p.time) {
struct timeval tv;
@@ -47,7 +68,8 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
tv.tv_sec = secs;
tv.tv_usec = 0;
perhapsSetRTC(RTCQualityFromNet, &tv);
// Set from phone RTC Quality to RTCQualityNTP since it should be approximately so
perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv);
}
nodeDB.updatePosition(getFrom(&mp), p);
@@ -65,7 +87,7 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
meshtastic_MeshPacket *PositionModule::allocReply()
{
if (ignoreRequest) {
return NULL;
return nullptr;
}
meshtastic_NodeInfoLite *node = service.refreshLocalMeshNode(); // should guarantee there is now a position
@@ -77,8 +99,9 @@ meshtastic_MeshPacket *PositionModule::allocReply()
// Populate a Position struct with ONLY the requested fields
meshtastic_Position p = meshtastic_Position_init_default; // Start with an empty structure
// if localPosition is totally empty, put our last saved position (lite) in there
if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0) {
localPosition = ConvertToPosition(node->position);
nodeDB.setLocalPosition(TypeConversions::ConvertToPosition(node->position));
}
localPosition.seq_number++;
@@ -142,8 +165,13 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
service.cancelSending(prevPacketId);
meshtastic_MeshPacket *p = allocReply();
if (p == nullptr) {
LOG_WARN("allocReply returned a nullptr");
return;
}
p->to = dest;
p->decoded.want_response = wantReplies;
p->decoded.want_response = config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ? false : wantReplies;
if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER)
p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
else
@@ -154,75 +182,142 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
p->channel = channel;
service.sendToMesh(p, RX_SRC_LOCAL, true);
if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER && config.power.is_power_saving) {
LOG_DEBUG("Starting next execution in 5 seconds and then going to sleep.\n");
sleepOnNextExecution = true;
setIntervalFromNow(5000);
}
}
#define RUNONCE_INTERVAL 5000;
int32_t PositionModule::runOnce()
{
if (sleepOnNextExecution == true) {
sleepOnNextExecution = false;
uint32_t nightyNightMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs);
LOG_DEBUG("Sleeping for %ims, then awaking to send position again.\n", nightyNightMs);
doDeepSleep(nightyNightMs, false);
}
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
// We limit our GPS broadcasts to a max rate
uint32_t now = millis();
uint32_t intervalMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs);
uint32_t msSinceLastSend = now - lastGpsSend;
// Only send packets if the channel util. is less than 25% utilized or we're a tracker with less than 40% utilized.
if (!airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) {
return RUNONCE_INTERVAL;
}
if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) {
// Only send packets if the channel is less than 40% utilized.
if (airTime->isTxAllowedChannelUtil()) {
if (hasValidPosition(node)) {
lastGpsSend = now;
if (hasValidPosition(node)) {
lastGpsSend = now;
lastGpsLatitude = node->position.latitude_i;
lastGpsLongitude = node->position.longitude_i;
lastGpsLatitude = node->position.latitude_i;
lastGpsLongitude = node->position.longitude_i;
// If we changed channels, ask everyone else for their latest info
// If we changed channels, ask everyone else for their latest info
bool requestReplies = currentGeneration != radioGeneration;
currentGeneration = radioGeneration;
LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", localPosition.timestamp, requestReplies);
sendOurPosition(NODENUM_BROADCAST, requestReplies);
}
} else if (config.position.position_broadcast_smart_enabled) {
const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
if (hasValidPosition(node2)) {
// The minimum time (in seconds) that would pass before we are able to send a new position packet.
const uint32_t minimumTimeThreshold =
getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
if (smartPosition.hasTraveledOverThreshold && msSinceLastSend >= minimumTimeThreshold) {
bool requestReplies = currentGeneration != radioGeneration;
currentGeneration = radioGeneration;
LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", localPosition.timestamp, requestReplies);
LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims, "
"minTimeInterval=%ims)\n",
localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold,
msSinceLastSend, minimumTimeThreshold);
sendOurPosition(NODENUM_BROADCAST, requestReplies);
}
}
} else if (config.position.position_broadcast_smart_enabled) {
// Only send packets if the channel is less than 25% utilized or we're a tracker.
if (airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) {
const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
if (hasValidPosition(node2)) {
// The minimum distance to travel before we are able to send a new position packet.
const uint32_t distanceTravelThreshold =
config.position.broadcast_smart_minimum_distance > 0 ? config.position.broadcast_smart_minimum_distance : 100;
// Set the current coords as our last ones, after we've compared distance with current and decided to send
lastGpsLatitude = node->position.latitude_i;
lastGpsLongitude = node->position.longitude_i;
// The minimum time (in seconds) that would pass before we are able to send a new position packet.
const uint32_t minimumTimeThreshold =
getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
// Determine the distance in meters between two points on the globe
float distanceTraveledSinceLastSend =
GeoCoord::latLongToMeter(lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, node->position.latitude_i * 1e-7,
node->position.longitude_i * 1e-7);
if ((abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold) && msSinceLastSend >= minimumTimeThreshold) {
bool requestReplies = currentGeneration != radioGeneration;
currentGeneration = radioGeneration;
LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims, "
"minTimeInterval=%ims)\n",
localPosition.timestamp, abs(distanceTraveledSinceLastSend), distanceTravelThreshold,
msSinceLastSend, minimumTimeThreshold);
sendOurPosition(NODENUM_BROADCAST, requestReplies);
// Set the current coords as our last ones, after we've compared distance with current and decided to send
lastGpsLatitude = node->position.latitude_i;
lastGpsLongitude = node->position.longitude_i;
/* Update lastGpsSend to now. This means if the device is stationary, then
getPref_position_broadcast_secs will still apply.
*/
lastGpsSend = now;
}
/* Update lastGpsSend to now. This means if the device is stationary, then
getPref_position_broadcast_secs will still apply.
*/
lastGpsSend = now;
}
}
}
return 5000; // to save power only wake for our callback occasionally
return RUNONCE_INTERVAL; // to save power only wake for our callback occasionally
}
struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition)
{
// The minimum distance to travel before we are able to send a new position packet.
const uint32_t distanceTravelThreshold = getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100);
// Determine the distance in meters between two points on the globe
float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter(
lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, currentPosition.latitude_i * 1e-7, currentPosition.longitude_i * 1e-7);
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("--------LAST POSITION------------------------------------\n");
LOG_DEBUG("lastGpsLatitude=%i, lastGpsLatitude=%i\n", lastGpsLatitude, lastGpsLongitude);
LOG_DEBUG("--------CURRENT POSITION---------------------------------\n");
LOG_DEBUG("currentPosition.latitude_i=%i, currentPosition.longitude_i=%i\n", lastGpsLatitude, lastGpsLongitude);
LOG_DEBUG("--------SMART POSITION-----------------------------------\n");
LOG_DEBUG("hasTraveledOverThreshold=%i, distanceTraveled=%d, distanceThreshold=% u\n",
abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold, abs(distanceTraveledSinceLastSend),
distanceTravelThreshold);
if (abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold) {
LOG_DEBUG("\n\n\nSMART SEEEEEEEEENDING\n\n\n");
}
#endif
return SmartPosition{.distanceTraveled = abs(distanceTraveledSinceLastSend),
.distanceThreshold = distanceTravelThreshold,
.hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold};
}
void PositionModule::handleNewPosition()
{
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
// We limit our GPS broadcasts to a max rate
uint32_t now = millis();
uint32_t msSinceLastSend = now - lastGpsSend;
if (hasValidPosition(node2)) {
auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
if (smartPosition.hasTraveledOverThreshold) {
bool requestReplies = currentGeneration != radioGeneration;
currentGeneration = radioGeneration;
LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims)\n",
localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold, msSinceLastSend);
sendOurPosition(NODENUM_BROADCAST, requestReplies);
// Set the current coords as our last ones, after we've compared distance with current and decided to send
lastGpsLatitude = node->position.latitude_i;
lastGpsLongitude = node->position.longitude_i;
/* Update lastGpsSend to now. This means if the device is stationary, then
getPref_position_broadcast_secs will still apply.
*/
lastGpsSend = now;
}
}
}

View File

@@ -31,6 +31,8 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
*/
void sendOurPosition(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false, uint8_t channel = 0);
void handleNewPosition();
protected:
/** Called to handle a particular incoming message
@@ -44,6 +46,18 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
/** Does our periodic broadcast */
virtual int32_t runOnce() override;
private:
struct SmartPosition getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition);
/** Only used in power saving trackers for now */
void clearPosition();
};
extern PositionModule *positionModule;
struct SmartPosition {
float distanceTraveled;
uint32_t distanceThreshold;
bool hasTraveledOverThreshold;
};
extern PositionModule *positionModule;

View File

@@ -29,7 +29,7 @@ class RangeTestModuleRadio : public SinglePortModule
uint32_t lastRxID = 0;
public:
RangeTestModuleRadio() : SinglePortModule("RangeTestModuleRadio", meshtastic_PortNum_TEXT_MESSAGE_APP)
RangeTestModuleRadio() : SinglePortModule("RangeTestModuleRadio", meshtastic_PortNum_RANGE_TEST_APP)
{
loopbackOk = true; // Allow locally generated messages to loop back to the client
}

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