Compare commits

...

263 Commits

Author SHA1 Message Date
Ben Meadors
e9bde80b57 change tft clear() to fillScreen() (#3077)
Maintains compatability with ESPI driver.

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2024-01-11 10:06:26 -06:00
Mark Trevor Birss
ccb5485510 Add SX1262 to M5Stack CoreInk (#3078)
* Update platformio.ini

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h
2024-01-11 10:06:02 -06:00
Ben Meadors
0d85069bec Heltec paper (#3069)
* Attempts at getting the Heltec Wireless Paper eink operational

* Bogus comment

* Fixing Support For Heltec Wireless Paper

---------

Co-authored-by: NfN Orange <orange@reveb.la>
2024-01-09 19:48:21 -06:00
GUVWAF
77ff1704db Allow button press if CannedMessage updown1 or rotary1 are not enabled (#3067)
`BUTTON_PIN` may be 0, which is equal to `inputbroker_pin_press` by default
2024-01-09 19:45:54 -06:00
GUVWAF
613a2bfb70 Update exception decoder for other platforms (#3070) 2024-01-09 19:45:03 -06:00
Ben Meadors
ea651c2f8f Remove gps_attempt_time and use broadcast interval instead (#3064) 2024-01-07 09:35:19 -06:00
Mictronics
c2afa879b8 Fix LED pinout for T-Echo board marked v1.0, date 2021-6-28 (#3051)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-07 07:40:12 -06:00
Ben Meadors
59253d9c78 Don't reboot after removing node from DB (#3065) 2024-01-07 07:37:13 -06:00
github-actions[bot]
be46f9ea24 [create-pull-request] automated change (#3063)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-06 15:23:40 -06:00
Ben Meadors
674fd32349 RP2040 Enter uf2 DFU mode (#3062)
* Pico enter dfu mode

* Ungaurd pico
2024-01-06 14:39:27 -06:00
Amin Husni
bacc525d0a Add Malaysia Region (#3053)
* Add Malaysia Region

Add frequency for 433MHz and 919MHz with specific power limit and limitation.

* Update RadioInterface.cpp

Formatting issues
2024-01-05 15:37:31 -06:00
github-actions[bot]
aa10a3ec40 [create-pull-request] automated change (#3055)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-04 18:54:44 -06:00
Jonathan Bennett
e3c768bf10 Update platformio.ini -- set target default to tbeam (#3054) 2024-01-04 12:22:45 -06:00
GUVWAF
943367edd0 Fix "watch GPIOs" feature of Remote Hardware module (#3047)
* Fix watch GPIO feature of Remote Hardware

* Add Remote Hardware messages to JSON output

* Add curly brackets

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-03 15:08:28 -06:00
Jonathan Bennett
4577646f8b Get rid of max-parallel build for rp2040 2023-12-29 17:49:25 -06:00
Jonathan Bennett
1ae02a9a28 Add dependencies for native build 2023-12-29 16:47:42 -06:00
Jonathan Bennett
28951ea1e0 Add libbluetooth-dev to build image 2023-12-29 12:35:42 -06:00
github-actions[bot]
2e9cc73ebb [create-pull-request] automated change (#3046)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-12-27 18:40:54 -06:00
Ben Meadors
dbac2b1cad Implemented enter (Uf2 usb) DFU mode admin message on NRF52 (#3045)
* Added enter DFU mode admin message

* Trunk
2023-12-27 14:26:40 -06:00
github-actions[bot]
2b7eb1e489 [create-pull-request] automated change (#3044)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-12-27 12:48:30 -06:00
S5NC
d401040e51 Remove old SX126x and SX128x boosted gain commented-out code (#2976)
* Update SX126xInterface.cpp

* Update SX128xInterface.cpp

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-27 08:18:26 -06:00
Wolfgang Nagele
5110de4838 Portduino reboot (#3033)
* Portduino reboot

* separate blocks

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-27 08:16:53 -06:00
GUVWAF
2d35f72d85 SimRadio: send queue status to phone (#3041)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-27 08:16:04 -06:00
Mictronics
d318d34c3c Fix #3032 (#3040)
* Fixed bug #3023 in upstream master. Wire.begin doesn't accept two arguments in RP2040 framework.

* Fix typo.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-27 08:15:38 -06:00
Wolfgang Nagele
06b4638f6b Allow override of HWID using environment variable (#3036)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-27 08:14:55 -06:00
GUVWAF
16c18d0da9 Add Traceroute, DetectionSensor and Paxcounter to MQTT JSON (#3043)
* Add Traceroute, DetectionSensor and Paxcounter to MQTT JSON

* Guard Paxcounter for ESP32 only
2023-12-27 08:14:25 -06:00
Jonathan Bennett
8d37d93e05 Hash function needs uint32_t for some platforms. (#3038) 2023-12-26 13:21:09 -06:00
Wolfgang Nagele
7334ee7349 Time Fix (#3035)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-25 16:40:16 -06:00
Wolfgang Nagele
ba98da55a7 Align glibc with Debian builder (#3034) 2023-12-25 09:47:19 -06:00
GUVWAF
db8f8db8e8 Don't disconnect WiFi when we're actively reconnecting (#3026)
WiFiEvents may happen asynchronously
2023-12-21 14:59:45 -06:00
GUVWAF
d88baea627 Make implicit ACKs work on MQTT (#3028)
Don't filter out messages we originally sent via LoRa
2023-12-21 14:59:16 -06:00
Mark Trevor Birss
16a3a32f2a [Add] SX1280 to linux native Portduino (#3023)
* Update PortduinoGlue.cpp

* Update PortduinoGlue.h

* Update main.cpp

* Update config-dist.yaml

* Update config-dist.yaml

* Fix whitespace in main.cpp

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2023-12-17 18:05:04 -06:00
Thomas Göttgens
a138e9cb6b Merge pull request #3020 from meshtastic/paxcounter
Include Libpax
2023-12-17 19:20:04 +01:00
Thomas Göttgens
86475a1719 admin getters and setters 2023-12-17 18:30:38 +01:00
Thomas Göttgens
c5a2dc758f rule of thumb, last minute changes are dumb. 2023-12-17 18:30:38 +01:00
Thomas Göttgens
add78a459b Include Libpax - WIP 2023-12-17 18:30:38 +01:00
Thomas Göttgens
f1b380882d Merge pull request #3022 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2023-12-17 18:30:19 +01:00
caveman99
bbe21766be [create-pull-request] automated change 2023-12-17 17:29:49 +00:00
Thomas Göttgens
dfa537415d Merge pull request #3021 from meshtastic/nodeinfo-shading
local variable and class variable may not be named the same
2023-12-17 17:09:44 +01:00
Thomas Göttgens
24c4ee9bfa local variable and class variable may not be named the same 2023-12-17 16:28:48 +01:00
Jonathan Bennett
71c0726838 Ignore keyboard input while sending CannedMessages packet 2023-12-16 23:03:41 -06:00
github-actions[bot]
45f90fb39b [create-pull-request] automated change (#3018)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-12-16 19:21:54 -06:00
Ben Meadors
1c6acfd734 Set NRF cpu brownout at 2.4V instead of running down to the limit (#3016) 2023-12-16 06:57:01 -06:00
Jonathan Bennett
c6ae66dcaa Add fallthrough option to avoid a GPS stuck off. 2023-12-14 21:39:41 -06:00
Jonathan Bennett
fc365a1fee Keep WiFi defines out of platforms without WiFi 2023-12-14 20:16:36 -06:00
Jonathan Bennett
6c1db94ae7 Add raspbian reboot and shutdown behavior 2023-12-14 19:53:42 -06:00
Thomas Göttgens
ded1cbf4dd Merge pull request #3015 from meshtastic/esp32s2fix
ESP32-S2 fix
2023-12-14 18:24:00 +01:00
Ben Meadors
399b9f8f6d Merge branch 'master' into esp32s2fix 2023-12-14 07:37:59 -06:00
Ben Meadors
4720b2874f Cpp-check warnings cleanup (#3014)
* cpp-check warnings cleanup

* Supressions and more fixes
2023-12-14 07:35:46 -06:00
Thomas Göttgens
1af3e0ddaa ESP32-S2 fix
ESP32-S2 does not have bluetooth
2023-12-14 13:40:22 +01:00
Ben Meadors
9f85279e74 Lost and found mode (#3012)
* Lost and found WIP

* 5 minutes

* ASCII bell character correction

* Memory
2023-12-13 17:43:20 -06:00
Jonathan Bennett
dd96848bec Change type to fix compilation in new code 2023-12-12 21:35:01 -06:00
Thomas Göttgens
4932e277f1 remove char counter when changing destination
shorten destination to make room for char counter, only on small displays.
2023-12-12 21:35:01 -06:00
Thomas Göttgens
dad05d7873 Select Node and channel in Canned Message module. 2023-12-12 21:35:01 -06:00
Thomas Göttgens
4b7fbeca29 only ever emit the up/down action if we have actual messages stored 2023-12-12 21:35:01 -06:00
Jonathan Bennett
2ebaea317a Refactor display handling add Raspbian TFT display (#2998)
* Refactor display handling add Raspbian TFT display

* Add missed change

* Add static casts

* Add missed TFT refactor for RAK14014

* Add missed GPIO configuration

* Adds Native keyboard input option

* Get the ifdefs right

* CannedMessage send via queue, not run immediately.

* Fixup systemd service file

* Add display blanking for Raspberry Pi

* Add a couple missed key definitions

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-12 20:27:31 -06:00
Ben Meadors
d14d2c89c3 RTTTL ringtones on T-Deck / T-Watch S3 and potentially more I2S audio enabled devices (#2917)
* WIP

* ESP8266 SAM fun

* I2S audio / ext. notification module

* Remove

* Protos

* Add use_i2s_as_buzzer from protos

* Fixes

* Stuff

* Thing

* Ext. Notification working(ish)

* Remove SAM commented code

* Trunk upgrade

* Trunk

* Fixes

* Slow not fast... :-|

* T-Deck and T-Watch don't use normal buttons

* Stop ext. notification nagging with touchscreen as well

* Add button gpio back for T-Deck, but guard against long-press during ext. notification

* Ext. notification wrap up

* Better place to guard against long-press false positives

* Adjust default gain and guard against non-i2s devices referencing audio-thread

* Simplify guard logic with a boolean

* Supress uninitMemberVar

* Protos merge got out of wack

* Trunk resolution

* Remove extra crap

* Cleanup and thread-interval

* Default to alert message buzzer and add nag timeout

* Formatting
2023-12-12 08:36:37 -06:00
Thomas Göttgens
35938392f1 Merge pull request #2739 from meshtastic/delivery-report
UI/UX: Display delivered message on incoming ACK.
2023-12-11 22:59:19 +01:00
Thomas Göttgens
d952da8b1e make sure the queue stays in te same order
the memory pool can NOT be iterated easily, since it's not a linear object.
2023-12-11 15:44:32 +01:00
Thomas Göttgens
385b29c977 we don't use the static MemoryPool anywhere, ditch dead code. 2023-12-11 15:35:22 +01:00
Thomas Göttgens
dc309f61e8 Look into tophone queue for the received packet.
- only works if we don't have a phone connected, but that is probably dsired
- this will send a copy of device-originating text messgaes to a connected phone. Breaking change.
- this will iterate the tophone queue by deconstructing and reconstructing it every time we look for an ID. Probably also mangles the queue oder since it aborts when a ID is found.
- Can we navigate the packet pool instead? If so, how?
- Let's keep this in draft state for now
2023-12-11 15:11:10 +01:00
Thomas Göttgens
512399c8f5 Merge branch 'delivery-report' of https://github.com/meshtastic/firmware into delivery-report 2023-12-11 12:38:22 +01:00
GUVWAF
5d94bb601a Distinguish between ACK/NAK by checking for error reason 2023-12-11 12:30:33 +01:00
Thomas Göttgens
796592b586 UI/UX: Display delivered message on incoming ACK.
Needs more work
2023-12-11 12:30:33 +01:00
Ben Meadors
d552ee3556 Add heltec-ht62 to CI (#3007) 2023-12-09 19:12:51 -06:00
Ben Meadors
14b31d4d14 Fix INA sensor dual use between environment telem and device battery reading (#3002) 2023-12-08 19:26:37 -06:00
Ken McGuire
4de6eb2e1d Reduce Serial Traffic on Heltec Wireless Trackers GNSS port (#3004)
* Fix typo in GNSS_MODEL defination and usages for the UC6580
Correct the $CFGSYS init string for the UC6580 to init the receiver for:
GPS L1 & L5 + BDS B1I & B2a + GLONASS L1 + GALILEO E1 & E5a + SBAS

* Reduce GNSS serial traffic on Helted Wireless Tracker
Turn off GSV and NOTIFY __TXT messages as neither are
necessary to Meshtastic operation.
2023-12-08 14:51:50 -06:00
Ben Meadors
abaa37133d Repeater and other power optimizations (#2999)
* End wire if we find no i2c devices

* Set tx-power to 0 on nrf bluetooth shutdown

* Change polling interval of PowerFSM to 100ms instead of 10ms

* Guard 3v3
2023-12-08 11:13:15 -06:00
Jonathan Bennett
5eac227550 Fix whitespace in workflow 2023-12-07 21:29:04 -06:00
Jonathan Bennett
671112f47d Update pull-request-artifacts config 2023-12-07 21:22:30 -06:00
Jonathan Bennett
8ea19d665a Update pull-request-artifacts 2023-12-07 20:22:22 -06:00
Ben Meadors
8f57cfaaf4 Makersense rp2040 variant fixes (#2997)
* WIP

* Do the right things

* Add to build matrix

* Yaml lint has annoyed me for the final time

* Fixes to variant
2023-12-07 17:12:51 -06:00
Ben Meadors
a54e3826e9 Remove truffle-hog tool for now since it's breaking CI 2023-12-07 07:14:41 -06:00
Ben Meadors
9188a9a1f2 Makersense RP2040 support (#2996)
* WIP

* Do the right things

* Add to build matrix

* Yaml lint has annoyed me for the final time
2023-12-06 21:42:06 -06:00
github-actions[bot]
17f1a450b2 [create-pull-request] automated change (#2995)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-12-06 18:14:41 -06:00
GUVWAF
ba021c97b2 Pico W: Handle Wi-Fi reconnects and update core (#2994)
* Fix time lost on the Pico W right after NTP
Shouldn't check for `#ifdef` as it will always be defined, but might be set to 0

* Handle reconnect for Wi-Fi on RP2040

* Update arduino-core for Wi-Fi + FreeRTOS fixes

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-06 15:49:56 -06:00
Ben Meadors
b4ad6b0f41 Added client-hidden role behavior (#2992)
* Added client-hidden role behavior

* Trunkt

* That line got all boogered up
2023-12-06 14:04:09 -06:00
Ben Meadors
28502a762f Added Known-Only rebroadcast mode behavior (#2993) 2023-12-06 14:02:41 -06:00
github-actions[bot]
89f0464233 [create-pull-request] automated change (#2991)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-12-06 06:17:50 -06:00
GUVWAF
46d02affe8 Pico W: Wi-Fi improvements (#2989)
* Pico W: Initial WiFi support: connects, but freezes after a while

* Update arduino-pico core to fix hang with Wi-Fi

* Add `picow` to workflow since it's different from `pico` now

* Show Wi-Fi frame on screen for all devices with Wi-Fi

* Pico W: Disable mDNS as it's unsupported with FreeRTOS

* Fix printing IP address

* Fix Raspbian build
2023-12-04 15:45:07 -06:00
Ken McGuire
62329ad11f Fix typo in GNSS_MODEL defination and usages for the UC6580 (#2988)
Correct the $CFGSYS init string for the UC6580 to init the receiver for:
GPS L1 & L5 + BDS B1I & B2a + GLONASS L1 + GALILEO E1 & E5a + SBAS
2023-12-04 12:35:26 -06:00
Thomas Göttgens
72b4fe51b1 radiolib is stable
just use one definition for all targets
2023-12-04 11:33:32 +01:00
Thomas Göttgens
07fc5df9c1 update trunk and linters to latest version 2023-12-03 13:02:14 +01:00
Thomas Göttgens
1c22d2c885 switch onebutton back to PIO registry, since they finally updated the lib there 2023-12-03 13:00:15 +01:00
github-actions[bot]
1f931a5e55 [create-pull-request] automated change (#2981)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-12-02 17:19:29 -06:00
Ben Meadors
31c4693c66 Missed the version bump apparently 2023-12-02 15:50:17 -06:00
GUVWAF
6ff61b3e04 Pico W: Initial Wi-Fi support (#2980)
* Pico W: Initial WiFi support: connects, but freezes after a while

* Update arduino-pico core to fix hang with Wi-Fi

* Add `picow` to workflow since it's different from `pico` now
2023-12-02 14:47:52 -06:00
S5NC
9e90b4af02 Update variant.h (#2930)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-02 07:46:25 -06:00
S5NC
2544733ad4 Standardise order for setting GPIO pin default values (#2942)
* Update SX126xInterface.cpp

* Update GPS.cpp

* Update TFTDisplay.cpp

* Update SX128xInterface.cpp

* Update EInkDisplay2.cpp

* trunk fmt

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2023-12-02 07:40:31 -06:00
Thomas Göttgens
1b6c11c5f1 tryfix crash (#2964)
* tryfix crash

* only use this when wifi is not enabled. (poking around)

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-02 07:00:20 -06:00
S5NC
4c69d06ac0 Update Power.cpp (#2979) 2023-12-02 06:30:00 -06:00
code8buster
85cbde75fe Merge pull request #2977 from meshtastic/g2-defaults
Factory Defaults for Nano G2 Ultra
2023-12-02 00:36:31 +00:00
GUVWAF
5e70fb9851 Distinguish between ACK/NAK by checking for error reason 2023-12-01 18:28:38 +01:00
Thomas Göttgens
6e967421a5 UI/UX: Display delivered message on incoming ACK.
Needs more work
2023-12-01 18:28:38 +01:00
Ben Meadors
a05bab35ad = 2023-12-01 07:17:38 -06:00
Ben Meadors
ac506a581c Merge branch 'master' into g2-defaults 2023-12-01 07:07:59 -06:00
Ben Meadors
def4ec5822 Always set user (nodeinfo) role to device config's current role (#2973) 2023-12-01 07:00:19 -06:00
Ben Meadors
209fb585b0 Default to what G2 comes with 2023-11-30 20:49:00 -06:00
S5NC
fb89482129 Set default LoRa SPI pins individually on ESP32 architecture (#2971)
* Each pin individually

* Correction

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-11-30 06:39:46 -06:00
Thomas Göttgens
8e742f2f80 Update portduino.ini 2023-11-30 11:53:47 +01:00
Thomas Göttgens
238cf8cdeb fix portduino 2023-11-30 11:53:47 +01:00
Thomas Göttgens
5df7f07f95 unpin radiolib 2023-11-30 11:53:47 +01:00
Thomas Göttgens
6fa026a78b fix radiolib API for 6.3.0 release 2023-11-30 10:59:01 +01:00
Jonathan Bennett
39743832ad Revert Portduino RadioLib to 6.1.0 2023-11-29 20:19:10 -06:00
Jonathan Bennett
bd2675caf1 Temporarily Pin RadioLib to 6.2.0 2023-11-29 20:19:10 -06:00
Jonathan Bennett
c489c251ab Pull in Portduino changes for Raspberry Pi support 2023-11-29 20:19:10 -06:00
Jonathan Bennett
14d03a2bda Initial implementation of I2C 2023-11-29 20:19:10 -06:00
Jonathan Bennett
423b8ad603 Adds real GPS support to Raspberry Pi arch 2023-11-29 20:19:10 -06:00
Jonathan Bennett
ce8342d3e5 Drop Pi HAL 2023-11-29 20:19:10 -06:00
Jonathan Bennett
57227c0f85 Add gpiochip setting 2023-11-29 20:19:10 -06:00
Jonathan Bennett
1ca2923658 Fix missed #if defined() logic 2023-11-29 20:19:10 -06:00
Jonathan Bennett
d10b1e1d00 Add better error reporting for RF95 init failure 2023-11-29 20:19:10 -06:00
Jonathan Bennett
d3e64350d9 Remove RADIOLIB_SPI_PARANOID compile option, as it does nothing 2023-11-29 20:19:10 -06:00
Jonathan Bennett
102efd4954 Move to portduino GPIO, adding user button support 2023-11-29 20:19:10 -06:00
S5NC
18cf8ca4fa Generalise SPI pin names (#2970)
* Generalise SPI pin names

* CS not NSS

* trunk fmt

* Update variant.h

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-11-29 15:51:05 -06:00
Ben Meadors
c7f6071f70 Enable IO2 toggling on RAK if the coast is clear (#2968)
* Enable IO2 toggling on RAK if the coast is clear

* Guard against monteops target which doesn't use 3V3 pin

* Also check for en_gpio = 0 to avoid re-setting the value
2023-11-28 20:40:51 -06:00
Thomas Göttgens
c7e3485dd7 Revert "same change for STM32WL - also update trunk"
This reverts commit f9fdb0f98d.
2023-11-26 14:49:11 +01:00
Thomas Göttgens
603e564db3 same change for STM32WL - also update trunk 2023-11-26 14:49:11 +01:00
Thomas Göttgens
ac318a9850 Swapped out crypto engine for one that also works with AES-256 2023-11-26 14:49:11 +01:00
Ben Meadors
1feb74f525 Add number of sats to default position flags (#2962) 2023-11-25 19:34:30 -06:00
Thomas Göttgens
d6fc1c314f WIP: Add battery level for Nimble 2023-11-25 16:03:39 +01:00
Thomas Göttgens
b3852322ef Add config example for Elecrow Hat
NFC
2023-11-24 14:40:20 +01:00
HookdomPonix
cbb8eb65ba Add USB detection to RAK4631 based boards. (#2956)
* Add support for the rak10701 board, no touch

* Moved tftblack fillin and changed teh src flags

* Added rak10701 to platformio.ini

* Add USB detection to RAK4631 units.

* Eliminate spurious symbol in comment field.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-11-22 10:30:55 -06:00
Jonathan Bennett
4712b1ca65 Add manual run option to package_raspbian.yml (#2954) 2023-11-22 07:17:48 -06:00
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
Thomas Göttgens
762166495f Merge branch 'master' into raspi-portduino 2023-08-17 10:06:34 +02: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
234 changed files with 5334 additions and 1820 deletions

View File

@@ -16,6 +16,19 @@ runs:
run: | run: |
sudo apt-get install -y cppcheck sudo apt-get install -y cppcheck
- name: Install libbluetooth
shell: bash
run: |
sudo apt-get install -y libbluetooth-dev
- name: Install libgpiod
shell: bash
run: |
sudo apt-get install -y libgpiod-dev
- name: Install libyaml-cpp
shell: bash
run: |
sudo apt-get install -y libyaml-cpp-dev
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:

View File

@@ -7,7 +7,7 @@
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc... 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 check in files that don't have real changes
- Please do not reformat lines that you didn't have to change the code on - 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. 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 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. - 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

@@ -66,6 +66,7 @@ jobs:
- board: tlora-v2-1-1_6 - board: tlora-v2-1-1_6
- board: tlora-v2-1-1_8 - board: tlora-v2-1-1_8
- board: tbeam - board: tbeam
- board: heltec-ht62-esp32c3-sx1262
- board: heltec-v1 - board: heltec-v1
- board: heltec-v2_0 - board: heltec-v2_0
- board: heltec-v2_1 - board: heltec-v2_1
@@ -103,7 +104,6 @@ jobs:
build-nrf52: build-nrf52:
strategy: strategy:
fail-fast: false fail-fast: false
max-parallel: 2
matrix: matrix:
include: include:
- board: rak4631 - board: rak4631
@@ -120,15 +120,25 @@ jobs:
build-rpi2040: build-rpi2040:
strategy: strategy:
fail-fast: false fail-fast: false
max-parallel: 2
matrix: matrix:
include: include:
- board: pico - board: pico
- board: picow
- board: rak11310 - board: rak11310
- board: senselora_rp2040
uses: ./.github/workflows/build_rpi2040.yml uses: ./.github/workflows/build_rpi2040.yml
with: with:
board: ${{ matrix.board }} 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: build-native:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -202,9 +212,20 @@ jobs:
repository: ${{github.event.pull_request.head.repo.full_name}} repository: ${{github.event.pull_request.head.repo.full_name}}
gather-artifacts: gather-artifacts:
permissions:
contents: write
pull-requests: write
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: 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: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
@@ -216,12 +237,15 @@ jobs:
with: with:
path: ./ path: ./
- name: Display structure of downloaded files
run: ls -R
- name: Get release version string - name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version id: version
- name: Move files up - 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 - name: Repackage in single firmware zip
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -233,6 +257,8 @@ jobs:
./firmware-*-ota.zip ./firmware-*-ota.zip
./device-*.sh ./device-*.sh
./device-*.bat ./device-*.bat
./meshtasticd_linux_arm64
./config-dist.yaml
retention-days: 90 retention-days: 90
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v3
@@ -262,14 +288,13 @@ jobs:
- name: Create request artifacts - name: Create request artifacts
continue-on-error: true # FIXME: Why are we getting 502, but things still work? continue-on-error: true # FIXME: Why are we getting 502, but things still work?
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }} if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
uses: gavv/pull-request-artifacts@v1.1.0 uses: gavv/pull-request-artifacts@v2.1.0
with: with:
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }} commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
artifacts-token: ${{ secrets.ARTIFACTS_TOKEN }} artifacts-token: ${{ secrets.ARTIFACTS_TOKEN }}
artifacts-repo: meshtastic/artifacts artifacts-repo: meshtastic/artifacts
artifacts-branch: device artifacts-branch: device
artifacts-dir: pr
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip artifacts: ./firmware-${{ steps.version.outputs.version }}.zip
release-artifacts: release-artifacts:
@@ -294,6 +319,13 @@ jobs:
name: firmware-${{ steps.version.outputs.version }} name: firmware-${{ steps.version.outputs.version }}
path: ./output path: ./output
- uses: actions/download-artifact@v3
with:
name: artifact-deb
- name: Display structure of downloaded files
run: ls -R
- name: Device scripts permissions - name: Device scripts permissions
run: | run: |
chmod +x ./output/device-install.sh chmod +x ./output/device-install.sh
@@ -347,6 +379,16 @@ jobs:
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
asset_content_type: application/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 - name: Bump version.properties
run: >- run: >-
bin/bump_version.py bin/bump_version.py

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

@@ -0,0 +1,62 @@
name: Package Raspbian
on:
workflow_call:
workflow_dispatch:
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

2
.trunk/.gitignore vendored
View File

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

View File

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

View File

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

View File

@@ -1,53 +1,43 @@
version: 0.1 version: 0.1
cli: cli:
version: 1.13.0 version: 1.17.2
plugins: plugins:
sources: sources:
- id: trunk - id: trunk
ref: v1.1.1 ref: v1.3.0
uri: https://github.com/trunk-io/plugins uri: https://github.com/trunk-io/plugins
lint: lint:
enabled: enabled:
- bandit@1.7.5 - bandit@1.7.5
- checkov@2.4.1 - checkov@3.1.9
- terrascan@1.18.3 - terrascan@1.18.5
- trivy@0.44.1 - trivy@0.47.0
- trufflehog@3.48.0 #- trufflehog@3.63.2-rc0
- taplo@0.8.1 - taplo@0.8.1
- ruff@0.0.284 - ruff@0.1.6
- yamllint@1.32.0
- isort@5.12.0 - isort@5.12.0
- markdownlint@0.35.0 - markdownlint@0.37.0
- oxipng@8.0.0 - oxipng@9.0.0
- svgo@3.0.2 - svgo@3.0.5
- actionlint@1.6.25 - actionlint@1.6.26
- flake8@6.1.0 - flake8@6.1.0
- hadolint@2.12.0 - hadolint@2.12.0
- shfmt@3.6.0 - shfmt@3.6.0
- shellcheck@0.9.0 - shellcheck@0.9.0
- black@23.7.0 - black@23.9.1
- git-diff-check - git-diff-check
- gitleaks@8.17.0 - gitleaks@8.18.1
- clang-format@16.0.3 - clang-format@16.0.3
- prettier@3.0.2 - prettier@3.1.0
disabled:
- taplo@0.8.1
- shellcheck@0.9.0
- shfmt@3.6.0
- oxipng@8.0.0
- actionlint@1.6.22
- markdownlint@0.35.0
- hadolint@2.12.0
- svgo@3.0.2
runtimes: runtimes:
enabled: enabled:
- python@3.10.8 - python@3.10.8
- go@1.19.5 - go@1.21.0
- node@18.12.1 - node@18.12.1
actions: actions:
disabled: disabled:
- trunk-announce - trunk-announce
- trunk-check-pre-push
- trunk-fmt-pre-commit
enabled: enabled:
- trunk-fmt-pre-commit
- trunk-check-pre-push
- trunk-upgrade-available - trunk-upgrade-available

View File

@@ -27,7 +27,7 @@ RUN wget https://raw.githubusercontent.com/platformio/platformio-core-installer/
source ~/.platformio/penv/bin/activate && \ source ~/.platformio/penv/bin/activate && \
./bin/build-native.sh ./bin/build-native.sh
FROM frolvlad/alpine-glibc FROM frolvlad/alpine-glibc:glibc-2.31
RUN apk --update add --no-cache g++ shadow && \ RUN apk --update add --no-cache g++ shadow && \
groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh
@@ -36,6 +36,6 @@ COPY --from=builder /tmp/firmware/release/meshtasticd_linux_amd64 /home/mesh/
USER mesh USER mesh
WORKDIR /home/mesh WORKDIR /home/mesh
CMD sh -cx "./meshtasticd_linux_amd64 --hwid '$RANDOM'" CMD sh -cx "./meshtasticd_linux_amd64 --hwid '${HWID:-$RANDOM}'"
HEALTHCHECK NONE HEALTHCHECK NONE

View File

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

View File

@@ -31,6 +31,9 @@ build_flags =
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120 -DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DSERIAL_BUFFER_SIZE=4096 -DSERIAL_BUFFER_SIZE=4096
-DLIBPAX_ARDUINO
-DLIBPAX_WIFI
-DLIBPAX_BLE
;-DDEBUG_HEAP ;-DDEBUG_HEAP
lib_deps = lib_deps =
@@ -39,7 +42,7 @@ lib_deps =
${environmental_base.lib_deps} ${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2 https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.1 h2zero/NimBLE-Arduino@^1.4.1
jgromes/RadioLib@^6.1.0 https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6 https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
@@ -57,4 +60,4 @@ lib_ignore =
; customize the partition table ; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables ; 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

@@ -11,11 +11,10 @@ build_flags =
-Isrc/platform/nrf52 -Isrc/platform/nrf52
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/> ${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/>
lib_deps= lib_deps=
${arduino_base.lib_deps} ${arduino_base.lib_deps}
jgromes/RadioLib@^6.1.0
lib_ignore = lib_ignore =
BluetoothOTA BluetoothOTA

View File

@@ -1,6 +1,6 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated ; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base] [portduino_base]
platform = https://github.com/meshtastic/platform-native.git#489ff929dca0bb768256ba2de45f95815111490f platform = https://github.com/meshtastic/platform-native.git#8a66ef82cf38a4135d85cbb5043d0e8ebbb8ba17
framework = arduino framework = arduino
build_src_filter = build_src_filter =
@@ -10,6 +10,7 @@ build_src_filter =
-<platform/nrf52/> -<platform/nrf52/>
-<platform/stm32wl/> -<platform/stm32wl/>
-<platform/rp2040> -<platform/rp2040>
-<mesh/wifi/>
-<mesh/http/> -<mesh/http/>
-<mesh/eth/> -<mesh/eth/>
-<modules/esp32> -<modules/esp32>
@@ -22,9 +23,9 @@ lib_deps =
${env.lib_deps} ${env.lib_deps}
${networking_base.lib_deps} ${networking_base.lib_deps}
rweather/Crypto@^0.4.0 rweather/Crypto@^0.4.0
jgromes/RadioLib@6.1.0
build_flags = build_flags =
${arduino_base.build_flags} ${arduino_base.build_flags}
-fPIC -fPIC
-Isrc/platform/portduino -Isrc/platform/portduino
-DRADIOLIB_EEPROM_UNSUPPORTED

View File

@@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets ; Common settings for rp2040 Processor based targets
[rp2040_base] [rp2040_base]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#0c33219f53faa035e188925ea1324f472e8b93d2 platform = https://github.com/maxgerhardt/platform-raspberrypi.git#612de5399d68b359053f1307ed223d400aea975c
extends = arduino_base extends = arduino_base
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.2.2 platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.2
board_build.core = earlephilhower board_build.core = earlephilhower
board_build.filesystem_size = 0.5m board_build.filesystem_size = 0.5m
@@ -12,7 +12,7 @@ build_flags =
-D__PLAT_RP2040__ -D__PLAT_RP2040__
# -D _POSIX_THREADS # -D _POSIX_THREADS
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> ${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/>
lib_ignore = lib_ignore =
BluetoothOTA BluetoothOTA
@@ -20,5 +20,4 @@ lib_ignore =
lib_deps = lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
${environmental_base.lib_deps} ${environmental_base.lib_deps}
jgromes/RadioLib@^6.1.0 rweather/Crypto
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b

View File

@@ -13,17 +13,16 @@ build_flags =
-DVECT_TAB_OFFSET=0x08000000 -DVECT_TAB_OFFSET=0x08000000
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040> ${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
board_upload.offset_address = 0x08000000 board_upload.offset_address = 0x08000000
upload_protocol = stlink upload_protocol = stlink
lib_deps = lib_deps =
${env.lib_deps} ${env.lib_deps}
jgromes/RadioLib@^6.1.0
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
https://github.com/littlefs-project/littlefs.git#v2.5.1 https://github.com/littlefs-project/littlefs.git#v2.5.1
https://github.com/stm32duino/STM32FreeRTOS.git#10.3.1 https://github.com/stm32duino/STM32FreeRTOS.git#10.3.1
lib_ignore = lib_ignore =
https://github.com/mathertel/OneButton#2.1.0 mathertel/OneButton

View File

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

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

@@ -0,0 +1,70 @@
### 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
# Module: RF95 # Elecrow Lora RFM95 IOT https://www.elecrow.com/lora-rfm95-iot-board-for-rpi.html
# Reset: 22
# CS: 7
# IRQ: 25
# Module: sx1280 # SX1280
# CS: 21
# IRQ: 16
# Busy: 20
# Reset: 18
### Set gpio chip to use in /dev/. Defaults to 0.
### Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
# gpiochip: 4
### Define GPIO buttons here:
GPIO:
# User: 6
### Define GPS
GPS:
# SerialPath: /dev/ttyS0
### Set up SPI displays here. Note that I2C displays are generally auto-detected.
Display:
### Waveshare 2.8inch RPi LCD
# Panel: ST7789
# CS: 8
# DC: 22 # Data/Command pin
# Backlight: 18
# Width: 240
# Height: 320
# Reset: 27
# Rotate: true
Touchscreen:
# Module: XPT2046
# CS: 7
# IRQ: 17
### Configure device for direct keyboard input
Input:
# KeyboardDevice: /dev/input/event0

View File

@@ -11,19 +11,22 @@ Meshtastic notes:
* version that's checked into meshtastic repo is based on: https://github.com/me21/EspArduinoExceptionDecoder * version that's checked into meshtastic repo is based on: https://github.com/me21/EspArduinoExceptionDecoder
which adds in ESP32 Backtrace decoding. which adds in ESP32 Backtrace decoding.
* this also updates the defaults to use ESP32, instead of ESP8266 and defaults to the built firmware.bin * this also updates the defaults to use ESP32, instead of ESP8266 and defaults to the built firmware.bin
* also updated the toolchain name, which will be set according to the platform
To use, copy the "Backtrace: 0x...." line to a file, e.g., backtrace.txt, then run: To use, copy the "Backtrace: 0x...." line to a file, e.g., backtrace.txt, then run:
$ bin/exception_decoder.py backtrace.txt $ bin/exception_decoder.py backtrace.txt
For a platform other than ESP32, use the -p option, e.g.:
$ bin/exception_decoder.py -p ESP32S3 backtrace.txt
To specify a specific .elf file, use the -e option, e.g.:
$ bin/exception_decoder.py -e firmware.elf backtrace.txt
""" """
import argparse import argparse
import os
import re import re
import subprocess import subprocess
from collections import namedtuple
import sys import sys
from collections import namedtuple
import os
EXCEPTIONS = [ EXCEPTIONS = [
"Illegal instruction", "Illegal instruction",
@@ -55,24 +58,39 @@ EXCEPTIONS = [
"LoadStorePrivilege: A load or store referenced a virtual address at a ring level less than CRING", "LoadStorePrivilege: A load or store referenced a virtual address at a ring level less than CRING",
"reserved", "reserved",
"LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads", "LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads",
"StoreProhibited: A store referenced a page mapped with an attribute that does not permit stores" "StoreProhibited: A store referenced a page mapped with an attribute that does not permit stores",
] ]
PLATFORMS = { PLATFORMS = {
"ESP8266": "lx106", "ESP8266": "xtensa-lx106",
"ESP32": "esp32" "ESP32": "xtensa-esp32",
"ESP32S3": "xtensa-esp32s3",
"ESP32C3": "riscv32-esp",
}
TOOLS = {
"ESP8266": "xtensa",
"ESP32": "xtensa-esp32",
"ESP32S3": "xtensa-esp32s3",
"ESP32C3": "riscv32-esp",
} }
BACKTRACE_REGEX = re.compile(r"(?:\s+(0x40[0-2](?:\d|[a-f]|[A-F]){5}):0x(?:\d|[a-f]|[A-F]){8})\b") BACKTRACE_REGEX = re.compile(
r"(?:\s+(0x40[0-2](?:\d|[a-f]|[A-F]){5}):0x(?:\d|[a-f]|[A-F]){8})\b"
)
EXCEPTION_REGEX = re.compile("^Exception \\((?P<exc>[0-9]*)\\):$") EXCEPTION_REGEX = re.compile("^Exception \\((?P<exc>[0-9]*)\\):$")
COUNTER_REGEX = re.compile('^epc1=(?P<epc1>0x[0-9a-f]+) epc2=(?P<epc2>0x[0-9a-f]+) epc3=(?P<epc3>0x[0-9a-f]+) ' COUNTER_REGEX = re.compile(
'excvaddr=(?P<excvaddr>0x[0-9a-f]+) depc=(?P<depc>0x[0-9a-f]+)$') "^epc1=(?P<epc1>0x[0-9a-f]+) epc2=(?P<epc2>0x[0-9a-f]+) epc3=(?P<epc3>0x[0-9a-f]+) "
"excvaddr=(?P<excvaddr>0x[0-9a-f]+) depc=(?P<depc>0x[0-9a-f]+)$"
)
CTX_REGEX = re.compile("^ctx: (?P<ctx>.+)$") CTX_REGEX = re.compile("^ctx: (?P<ctx>.+)$")
POINTER_REGEX = re.compile('^sp: (?P<sp>[0-9a-f]+) end: (?P<end>[0-9a-f]+) offset: (?P<offset>[0-9a-f]+)$') POINTER_REGEX = re.compile(
STACK_BEGIN = '>>>stack>>>' "^sp: (?P<sp>[0-9a-f]+) end: (?P<end>[0-9a-f]+) offset: (?P<offset>[0-9a-f]+)$"
STACK_END = '<<<stack<<<' )
STACK_BEGIN = ">>>stack>>>"
STACK_END = "<<<stack<<<"
STACK_REGEX = re.compile( STACK_REGEX = re.compile(
'^(?P<off>[0-9a-f]+):\W+(?P<c1>[0-9a-f]+) (?P<c2>[0-9a-f]+) (?P<c3>[0-9a-f]+) (?P<c4>[0-9a-f]+)(\W.*)?$') "^(?P<off>[0-9a-f]+):\W+(?P<c1>[0-9a-f]+) (?P<c2>[0-9a-f]+) (?P<c3>[0-9a-f]+) (?P<c4>[0-9a-f]+)(\W.*)?$"
)
StackLine = namedtuple("StackLine", ["offset", "content"]) StackLine = namedtuple("StackLine", ["offset", "content"])
@@ -96,15 +114,18 @@ class ExceptionDataParser(object):
self.stack = [] self.stack = []
def _parse_backtrace(self, line): def _parse_backtrace(self, line):
if line.startswith('Backtrace:'): if line.startswith("Backtrace:"):
self.stack = [StackLine(offset=0, content=(addr,)) for addr in BACKTRACE_REGEX.findall(line)] self.stack = [
StackLine(offset=0, content=(addr,))
for addr in BACKTRACE_REGEX.findall(line)
]
return None return None
return self._parse_backtrace return self._parse_backtrace
def _parse_exception(self, line): def _parse_exception(self, line):
match = EXCEPTION_REGEX.match(line) match = EXCEPTION_REGEX.match(line)
if match is not None: if match is not None:
self.exception = int(match.group('exc')) self.exception = int(match.group("exc"))
return self._parse_counters return self._parse_counters
return self._parse_exception return self._parse_exception
@@ -144,14 +165,22 @@ class ExceptionDataParser(object):
if line != STACK_END: if line != STACK_END:
match = STACK_REGEX.match(line) match = STACK_REGEX.match(line)
if match is not None: if match is not None:
self.stack.append(StackLine(offset=match.group("off"), self.stack.append(
content=(match.group("c1"), match.group("c2"), match.group("c3"), StackLine(
match.group("c4")))) offset=match.group("off"),
content=(
match.group("c1"),
match.group("c2"),
match.group("c3"),
match.group("c4"),
),
)
)
return self._parse_stack_line return self._parse_stack_line
return None return None
def parse_file(self, file, platform, stack_only=False): def parse_file(self, file, platform, stack_only=False):
if platform == 'ESP32': if platform != "ESP8266":
func = self._parse_backtrace func = self._parse_backtrace
else: else:
func = self._parse_exception func = self._parse_exception
@@ -175,7 +204,9 @@ class AddressResolver(object):
self._address_map = {} self._address_map = {}
def _lookup(self, addresses): def _lookup(self, addresses):
cmd = [self._tool, "-aipfC", "-e", self._elf] + [addr for addr in addresses if addr is not None] cmd = [self._tool, "-aipfC", "-e", self._elf] + [
addr for addr in addresses if addr is not None
]
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
output = subprocess.check_output(cmd) output = subprocess.check_output(cmd)
@@ -190,19 +221,27 @@ class AddressResolver(object):
match = line_regex.match(line) match = line_regex.match(line)
if match is None: if match is None:
if last is not None and line.startswith('(inlined by)'): if last is not None and line.startswith("(inlined by)"):
line = line [12:].strip() line = line[12:].strip()
self._address_map[last] += ("\n \-> inlined by: " + line) self._address_map[last] += "\n \-> inlined by: " + line
continue continue
if match.group("result") == '?? ??:0': if match.group("result") == "?? ??:0":
continue continue
self._address_map[match.group("addr")] = match.group("result") self._address_map[match.group("addr")] = match.group("result")
last = match.group("addr") last = match.group("addr")
def fill(self, parser): def fill(self, parser):
addresses = [parser.epc1, parser.epc2, parser.epc3, parser.excvaddr, parser.sp, parser.end, parser.offset] addresses = [
parser.epc1,
parser.epc2,
parser.epc3,
parser.excvaddr,
parser.sp,
parser.end,
parser.offset,
]
for line in parser.stack: for line in parser.stack:
addresses.extend(line.content) addresses.extend(line.content)
@@ -257,8 +296,10 @@ def print_stack(lines, resolver):
def print_result(parser, resolver, platform, full=True, stack_only=False): def print_result(parser, resolver, platform, full=True, stack_only=False):
if platform == 'ESP8266' and not stack_only: if platform == "ESP8266" and not stack_only:
print('Exception: {} ({})'.format(parser.exception, EXCEPTIONS[parser.exception])) print(
"Exception: {} ({})".format(parser.exception, EXCEPTIONS[parser.exception])
)
print("") print("")
print_addr("epc1", parser.epc1, resolver) print_addr("epc1", parser.epc1, resolver)
@@ -285,15 +326,33 @@ def print_result(parser, resolver, platform, full=True, stack_only=False):
def parse_args(): def parse_args():
parser = argparse.ArgumentParser(description="decode ESP Stacktraces.") parser = argparse.ArgumentParser(description="decode ESP Stacktraces.")
parser.add_argument("-p", "--platform", help="The platform to decode from", choices=PLATFORMS.keys(), parser.add_argument(
default="ESP32") "-p",
parser.add_argument("-t", "--tool", help="Path to the xtensa toolchain", "--platform",
default="~/.platformio/packages/toolchain-xtensa32/") help="The platform to decode from",
parser.add_argument("-e", "--elf", help="path to elf file", choices=PLATFORMS.keys(),
default=".pio/build/esp32/firmware.elf") default="ESP32",
parser.add_argument("-f", "--full", help="Print full stack dump", action="store_true") )
parser.add_argument("-s", "--stack_only", help="Decode only a stractrace", action="store_true") parser.add_argument(
parser.add_argument("file", help="The file to read the exception data from ('-' for STDIN)", default="-") "-t",
"--tool",
help="Path to the toolchain (without specific platform)",
default="~/.platformio/packages/toolchain-",
)
parser.add_argument(
"-e", "--elf", help="path to elf file", default=".pio/build/tbeam/firmware.elf"
)
parser.add_argument(
"-f", "--full", help="Print full stack dump", action="store_true"
)
parser.add_argument(
"-s", "--stack_only", help="Decode only a stractrace", action="store_true"
)
parser.add_argument(
"file",
help="The file to read the exception data from ('-' for STDIN)",
default="-",
)
return parser.parse_args() return parser.parse_args()
@@ -309,10 +368,12 @@ if __name__ == "__main__":
sys.exit(1) sys.exit(1)
file = open(args.file, "r") file = open(args.file, "r")
addr2line = os.path.join(os.path.abspath(os.path.expanduser(args.tool)), addr2line = os.path.join(
"bin/xtensa-" + PLATFORMS[args.platform] + "-elf-addr2line") os.path.abspath(os.path.expanduser(args.tool + TOOLS[args.platform])),
if os.name == 'nt': "bin/" + PLATFORMS[args.platform] + "-elf-addr2line",
addr2line += '.exe' )
if os.name == "nt":
addr2line += ".exe"
if not os.path.exists(addr2line): if not os.path.exists(addr2line):
print("ERROR: addr2line not found (" + addr2line + ")") print("ERROR: addr2line not found (" + addr2line + ")")

12
bin/meshtasticd.service Normal file
View File

@@ -0,0 +1,12 @@
[Unit]
Description=Meshtastic Native Daemon
After=network-online.target
[Service]
User=root
Group=root
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

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

View File

@@ -2,7 +2,7 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[platformio] [platformio]
;default_envs = tbeam default_envs = tbeam
;default_envs = pico ;default_envs = pico
;default_envs = tbeam-s3-core ;default_envs = tbeam-s3-core
;default_envs = tbeam0.7 ;default_envs = tbeam0.7
@@ -26,7 +26,8 @@
;default_envs = meshtastic-dr-dev ;default_envs = meshtastic-dr-dev
;default_envs = m5stack-coreink ;default_envs = m5stack-coreink
;default_envs = rak4631 ;default_envs = rak4631
default_envs = wio-e5 ;default_envs = rak10701
;default_envs = wio-e5
extra_configs = extra_configs =
arch/*/*.ini arch/*/*.ini
@@ -67,10 +68,11 @@ build_flags = -Wno-missing-field-initializers
monitor_speed = 115200 monitor_speed = 115200
lib_deps = lib_deps =
jgromes/RadioLib@^6.3.0
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306 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 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 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 https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.7 nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1 erriez/ErriezCRC32@^1.0.1
@@ -92,7 +94,7 @@ lib_deps =
end2endzone/NonBlockingRTTTL@^1.3.0 end2endzone/NonBlockingRTTTL@^1.3.0
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0 build_flags = ${env.build_flags} -Os
build_src_filter = ${env.build_src_filter} -<platform/portduino/> build_src_filter = ${env.build_src_filter} -<platform/portduino/>
; Common libs for communicating over TCP/IP networks such as MQTT ; Common libs for communicating over TCP/IP networks such as MQTT
@@ -113,6 +115,7 @@ lib_deps =
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400 https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
boschsensortec/BME68x Sensor Library@^1.1.40407 boschsensortec/BME68x Sensor Library@^1.1.40407
adafruit/Adafruit MCP9808 Library@^2.0.0 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 INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0 adafruit/Adafruit INA219@^1.2.0
adafruit/Adafruit SHTC3 Library@^1.0.0 adafruit/Adafruit SHTC3 Library@^1.0.0
@@ -121,4 +124,4 @@ lib_deps =
adafruit/Adafruit PM25 AQI Sensor@^1.0.6 adafruit/Adafruit PM25 AQI Sensor@^1.0.6
adafruit/Adafruit MPU6050@^2.2.4 adafruit/Adafruit MPU6050@^2.2.4
adafruit/Adafruit LIS3DH@^1.2.4 adafruit/Adafruit LIS3DH@^1.2.4
https://github.com/lewisxhe/BMA423_Library@^0.0.1 https://github.com/lewisxhe/BMA423_Library@^0.0.1

View File

@@ -42,7 +42,7 @@ namespace concurrency
class AccelerometerThread : public concurrency::OSThread class AccelerometerThread : public concurrency::OSThread
{ {
public: public:
AccelerometerThread(ScanI2C::DeviceType type = ScanI2C::DeviceType::NONE) : OSThread("AccelerometerThread") explicit AccelerometerThread(ScanI2C::DeviceType type) : OSThread("AccelerometerThread")
{ {
if (accelerometer_found.port == ScanI2C::I2CPort::NO_I2C) { if (accelerometer_found.port == ScanI2C::I2CPort::NO_I2C) {
LOG_DEBUG("AccelerometerThread disabling due to no sensors found\n"); LOG_DEBUG("AccelerometerThread disabling due to no sensors found\n");

View File

@@ -10,7 +10,7 @@ namespace concurrency
class AmbientLightingThread : public concurrency::OSThread class AmbientLightingThread : public concurrency::OSThread
{ {
public: public:
AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLightingThread") explicit AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLightingThread")
{ {
// Uncomment to test module // Uncomment to test module
// moduleConfig.ambient_lighting.led_state = true; // moduleConfig.ambient_lighting.led_state = true;

77
src/AudioThread.h Normal file
View File

@@ -0,0 +1,77 @@
#pragma once
#include "PowerFSM.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
#include "main.h"
#include "sleep.h"
#ifdef HAS_I2S
#include <AudioFileSourcePROGMEM.h>
#include <AudioGeneratorRTTTL.h>
#include <AudioOutputI2S.h>
#include <ESP8266SAM.h>
#define AUDIO_THREAD_INTERVAL_MS 100
class AudioThread : public concurrency::OSThread
{
public:
AudioThread() : OSThread("AudioThread") { initOutput(); }
void beginRttl(const void *data, uint32_t len)
{
setCPUFast(true);
rtttlFile = new AudioFileSourcePROGMEM(data, len);
i2sRtttl = new AudioGeneratorRTTTL();
i2sRtttl->begin(rtttlFile, audioOut);
}
bool isPlaying()
{
if (i2sRtttl != nullptr) {
return i2sRtttl->isRunning() && i2sRtttl->loop();
}
return false;
}
void stop()
{
if (i2sRtttl != nullptr) {
i2sRtttl->stop();
delete i2sRtttl;
i2sRtttl = nullptr;
}
if (rtttlFile != nullptr) {
delete rtttlFile;
rtttlFile = nullptr;
}
setCPUFast(false);
}
protected:
int32_t runOnce() override
{
canSleep = true; // Assume we should not keep the board awake
// if (i2sRtttl != nullptr && i2sRtttl->isRunning()) {
// i2sRtttl->loop();
// }
return AUDIO_THREAD_INTERVAL_MS;
}
private:
void initOutput()
{
audioOut = new AudioOutputI2S(1, AudioOutputI2S::EXTERNAL_I2S);
audioOut->SetPinout(DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT);
audioOut->SetGain(0.2);
};
AudioGeneratorRTTTL *i2sRtttl = nullptr;
AudioOutputI2S *audioOut;
AudioFileSourcePROGMEM *rtttlFile;
};
#endif

View File

@@ -5,6 +5,7 @@
#include "configuration.h" #include "configuration.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "main.h" #include "main.h"
#include "modules/ExternalNotificationModule.h"
#include "power.h" #include "power.h"
#include <OneButton.h> #include <OneButton.h>
@@ -36,6 +37,9 @@ class ButtonThread : public concurrency::OSThread
#endif #endif
#ifdef BUTTON_PIN_TOUCH #ifdef BUTTON_PIN_TOUCH
OneButton userButtonTouch; OneButton userButtonTouch;
#endif
#if defined(ARCH_RASPBERRY_PI)
OneButton userButton;
#endif #endif
static bool shutdown_on_long_stop; static bool shutdown_on_long_stop;
@@ -45,8 +49,14 @@ class ButtonThread : public concurrency::OSThread
// callback returns the period for the next callback invocation (or 0 if we should no longer be called) // callback returns the period for the next callback invocation (or 0 if we should no longer be called)
ButtonThread() : OSThread("Button") ButtonThread() : OSThread("Button")
{ {
#ifdef BUTTON_PIN #if defined(ARCH_RASPBERRY_PI) || defined(BUTTON_PIN)
#if defined(ARCH_RASPBERRY_PI)
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC)
userButton = OneButton(settingsMap[user], true, true);
#elif defined(BUTTON_PIN)
userButton = OneButton(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, true, true); userButton = OneButton(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, true, true);
#endif
#ifdef INPUT_PULLUP_SENSE #ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did // Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP_SENSE); pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP_SENSE);
@@ -58,8 +68,13 @@ class ButtonThread : public concurrency::OSThread
userButton.attachMultiClick(userButtonMultiPressed); userButton.attachMultiClick(userButtonMultiPressed);
userButton.attachLongPressStart(userButtonPressedLongStart); userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop); userButton.attachLongPressStop(userButtonPressedLongStop);
#if defined(ARCH_RASPBERRY_PI)
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC)
wakeOnIrq(settingsMap[user], FALLING);
#else
wakeOnIrq(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, FALLING); wakeOnIrq(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, FALLING);
#endif #endif
#endif
#ifdef BUTTON_PIN_ALT #ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true); userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
#ifdef INPUT_PULLUP_SENSE #ifdef INPUT_PULLUP_SENSE
@@ -87,9 +102,14 @@ class ButtonThread : public concurrency::OSThread
{ {
canSleep = true; // Assume we should not keep the board awake canSleep = true; // Assume we should not keep the board awake
#ifdef BUTTON_PIN #if defined(BUTTON_PIN)
userButton.tick(); userButton.tick();
canSleep &= userButton.isIdle(); canSleep &= userButton.isIdle();
#elif defined(ARCH_RASPBERRY_PI)
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC) {
userButton.tick();
canSleep &= userButton.isIdle();
}
#endif #endif
#ifdef BUTTON_PIN_ALT #ifdef BUTTON_PIN_ALT
userButtonAlt.tick(); userButtonAlt.tick();
@@ -118,6 +138,14 @@ class ButtonThread : public concurrency::OSThread
#ifdef BUTTON_PIN #ifdef BUTTON_PIN
if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) != if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
moduleConfig.canned_message.inputbroker_pin_press) || moduleConfig.canned_message.inputbroker_pin_press) ||
!(moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.rotary1_enabled) ||
!moduleConfig.canned_message.enabled) {
powerFSM.trigger(EVENT_PRESS);
}
#endif
#if defined(ARCH_RASPBERRY_PI)
if ((settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC) &&
(settingsMap[user] != moduleConfig.canned_message.inputbroker_pin_press) ||
!moduleConfig.canned_message.enabled) { !moduleConfig.canned_message.enabled) {
powerFSM.trigger(EVENT_PRESS); powerFSM.trigger(EVENT_PRESS);
} }
@@ -179,6 +207,12 @@ class ButtonThread : public concurrency::OSThread
static void userButtonPressedLongStart() static void userButtonPressedLongStart()
{ {
#ifdef T_DECK
// False positive long-press triggered on T-Deck with i2s audio, so short circuit
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
return;
}
#endif
if (millis() > 30 * 1000) { if (millis() > 30 * 1000) {
LOG_DEBUG("Long press start!\n"); LOG_DEBUG("Long press start!\n");
longPressTime = millis(); longPressTime = millis();

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

@@ -19,6 +19,11 @@
#include "meshUtils.h" #include "meshUtils.h"
#include "sleep.h" #include "sleep.h"
// Working USB detection for powered/charging states on the RAK platform
#ifdef NRF_APM
#include "nrfx_power.h"
#endif
#ifdef DEBUG_HEAP_MQTT #ifdef DEBUG_HEAP_MQTT
#include "mqtt/MQTT.h" #include "mqtt/MQTT.h"
#include "target_specific.h" #include "target_specific.h"
@@ -52,6 +57,7 @@ static const adc_atten_t atten = ADC_ATTENUATION;
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) #if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
INA260Sensor ina260Sensor; INA260Sensor ina260Sensor;
INA219Sensor ina219Sensor; INA219Sensor ina219Sensor;
INA3221Sensor ina3221Sensor;
#endif #endif
#ifdef HAS_PMU #ifdef HAS_PMU
@@ -175,9 +181,21 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint32_t raw = 0; uint32_t raw = 0;
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#ifndef BAT_MEASURE_ADC_UNIT // ADC1 #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++) { for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += adc1_get_raw(adc_channel); raw += adc1_get_raw(adc_channel);
} }
#ifdef ADC_CTRL
if (heltec_version == 5) {
digitalWrite(ADC_CTRL, LOW);
}
#endif
#else // ADC2 #else // ADC2
int32_t adc_buf = 0; int32_t adc_buf = 0;
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) { for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
@@ -269,10 +287,14 @@ class AnalogBatteryLevel : public HasBatteryLevel
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) #if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO)
uint16_t getINAVoltage() 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(); 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(); return ina260Sensor.getBusVoltageMv();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA3221].first ==
config.power.device_battery_ina_address) {
return ina3221Sensor.getBusVoltageMv();
} }
return 0; return 0;
} }
@@ -282,11 +304,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
if (!config.power.device_battery_ina_address) { if (!config.power.device_battery_ina_address) {
return false; 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()) if (!ina219Sensor.isInitialized())
return ina219Sensor.runOnce() > 0; return ina219Sensor.runOnce() > 0;
return ina219Sensor.isRunning(); 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()) if (!ina260Sensor.isInitialized())
return ina260Sensor.runOnce() > 0; return ina260Sensor.runOnce() > 0;
return ina260Sensor.isRunning(); return ina260Sensor.isRunning();
@@ -379,11 +402,8 @@ bool Power::analogInit()
*/ */
bool Power::setup() bool Power::setup()
{ {
bool found = axpChipInit(); bool found = axpChipInit() || analogInit();
if (!found) {
found = analogInit();
}
enabled = found; enabled = found;
low_voltage_counter = 0; low_voltage_counter = 0;
@@ -412,9 +432,9 @@ void Power::shutdown()
ledOff(PIN_LED2); ledOff(PIN_LED2);
#endif #endif
#ifdef PIN_LED3 #ifdef PIN_LED3
ledOff(PIN_LED2); ledOff(PIN_LED3);
#endif #endif
doDeepSleep(DELAY_FOREVER); doDeepSleep(DELAY_FOREVER, false);
#endif #endif
} }
@@ -442,10 +462,25 @@ void Power::readPowerStatus()
} }
} }
OptionalBool NRF_USB = OptFalse;
#ifdef NRF_APM // Section of code detects USB power on the RAK4631 and updates the power states. Takes 20 seconds or so to detect
// changes.
nrfx_power_usb_state_t nrf_usb_state = nrfx_power_usbstatus_get();
if (nrf_usb_state == NRFX_POWER_USB_STATE_DISCONNECTED) {
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
NRF_USB = OptFalse;
} else {
powerFSM.trigger(EVENT_POWER_CONNECTED);
NRF_USB = OptTrue;
}
#endif
// Notify any status instances that are observing us // Notify any status instances that are observing us
const PowerStatus powerStatus2 = const PowerStatus powerStatus2 = PowerStatus(
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVbusIn() ? OptTrue : OptFalse, hasBattery ? OptTrue : OptFalse, batteryLevel->isVbusIn() || NRF_USB == OptTrue ? OptTrue : OptFalse,
batteryLevel->isCharging() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent); batteryLevel->isCharging() || NRF_USB == OptTrue ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(), LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent()); powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2); newStatus.notifyObservers(&powerStatus2);
@@ -859,4 +894,4 @@ bool Power::axpChipInit()
#else #else
return false; return false;
#endif #endif
} }

View File

@@ -45,7 +45,7 @@ static void sdsEnter()
{ {
LOG_DEBUG("Enter state: SDS\n"); LOG_DEBUG("Enter state: SDS\n");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw // 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; extern Power *power;
@@ -154,9 +154,6 @@ static void darkEnter()
{ {
setBluetoothEnable(true); setBluetoothEnable(true);
screen->setOn(false); screen->setOn(false);
#ifdef KB_POWERON
digitalWrite(KB_POWERON, LOW);
#endif
} }
static void serialEnter() static void serialEnter()
@@ -184,9 +181,6 @@ static void powerEnter()
} else { } else {
screen->setOn(true); screen->setOn(true);
setBluetoothEnable(true); setBluetoothEnable(true);
#ifdef KB_POWERON
digitalWrite(KB_POWERON, HIGH);
#endif
// within enter() the function getState() returns the state we came from // within enter() the function getState() returns the state we came from
if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 && if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
strcmp(powerFSM.getState()->name, "DARK") != 0) { strcmp(powerFSM.getState()->name, "DARK") != 0) {
@@ -217,9 +211,6 @@ static void onEnter()
LOG_DEBUG("Enter state: ON\n"); LOG_DEBUG("Enter state: ON\n");
screen->setOn(true); screen->setOn(true);
setBluetoothEnable(true); setBluetoothEnable(true);
#ifdef KB_POWERON
digitalWrite(KB_POWERON, HIGH);
#endif
} }
static void onIdle() static void onIdle()
@@ -254,6 +245,8 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup() void PowerFSM_setup()
{ {
bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0); 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(); bool hasPower = isPowered();
LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0); LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0);
@@ -357,12 +350,12 @@ void PowerFSM_setup()
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
"Screen-on timeout"); "Screen-on timeout");
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
#ifdef ARCH_ESP32 #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 // 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, powerFSM.add_timed_transition(&stateNB, &stateLS,
getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL,
"Min wake timeout"); "Min wake timeout");

View File

@@ -21,7 +21,7 @@ class PowerFSMThread : public OSThread
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake /// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
/// cpu for serial rx - FIXME) /// cpu for serial rx - FIXME)
const auto state = powerFSM.getState(); const State *state = powerFSM.getState();
canSleep = (state != &statePOWER) && (state != &stateSERIAL); canSleep = (state != &statePOWER) && (state != &stateSERIAL);
if (powerStatus->getHasUSB()) { if (powerStatus->getHasUSB()) {
@@ -33,7 +33,7 @@ class PowerFSMThread : public OSThread
powerFSM.trigger(EVENT_SHUTDOWN); powerFSM.trigger(EVENT_SHUTDOWN);
} }
return 10; return 100;
} }
}; };

View File

@@ -67,6 +67,7 @@ class OSThread : public Thread
* Returns desired period for next invocation (or RUN_SAME for no change) * Returns desired period for next invocation (or RUN_SAME for no change)
*/ */
virtual int32_t runOnce() = 0; virtual int32_t runOnce() = 0;
bool sleepOnNextExecution = false;
// Do not override this // Do not override this
virtual void run(); virtual void run();

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 #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 /// Convert a preprocessor name into a quoted string
#define xstr(s) str(s) #define xstr(s) ystr(s)
#define str(s) #s #define ystr(s) #s
/// Convert a preprocessor name into a quoted string and if that string is empty use "unset" /// 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") #define optstr(s) (xstr(s)[0] ? xstr(s) : "unset")
@@ -111,6 +111,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MCP9808_ADDR 0x18 #define MCP9808_ADDR 0x18
#define INA_ADDR 0x40 #define INA_ADDR 0x40
#define INA_ADDR_ALTERNATE 0x41 #define INA_ADDR_ALTERNATE 0x41
#define INA3221_ADDR 0x42
#define QMC6310_ADDR 0x1C #define QMC6310_ADDR 0x1C
#define QMI8658_ADDR 0x6B #define QMI8658_ADDR 0x6B
#define QMC5883L_ADDR 0x1E #define QMC5883L_ADDR 0x1E
@@ -187,6 +188,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef HAS_TELEMETRY #ifndef HAS_TELEMETRY
#define HAS_TELEMETRY 0 #define HAS_TELEMETRY 0
#endif #endif
#ifndef HAS_SENSOR
#define HAS_SENSOR 0
#endif
#ifndef HAS_RADIO #ifndef HAS_RADIO
#define HAS_RADIO 0 #define HAS_RADIO 0
#endif #endif

View File

@@ -25,6 +25,7 @@ class ScanI2C
BMP_280, BMP_280,
INA260, INA260,
INA219, INA219,
INA3221,
MCP9808, MCP9808,
SHT31, SHT31,
SHTC3, SHTC3,

View File

@@ -2,7 +2,9 @@
#include "concurrency/LockGuard.h" #include "concurrency/LockGuard.h"
#include "configuration.h" #include "configuration.h"
#if defined(ARCH_RASPBERRY_PI)
#include "linux/LinuxHardwareI2C.h"
#endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "main.h" // atecc #include "main.h" // atecc
#endif #endif
@@ -162,7 +164,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
for (addr.address = 1; addr.address < 127; addr.address++) { for (addr.address = 1; addr.address < 127; addr.address++) {
i2cBus->beginTransmission(addr.address); i2cBus->beginTransmission(addr.address);
#ifdef ARCH_PORTDUINO
if (i2cBus->read() != -1)
err = 0;
else
err = 2;
#else
err = i2cBus->endTransmission(); err = i2cBus->endTransmission();
#endif
type = NONE; type = NONE;
if (err == 0) { if (err == 0) {
LOG_DEBUG("I2C device found at address 0x%x\n", addr.address); LOG_DEBUG("I2C device found at address 0x%x\n", addr.address);
@@ -251,7 +260,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
type = INA219; type = INA219;
} }
break; break;
case INA3221_ADDR:
LOG_INFO("INA3221 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = INA3221;
break;
case MCP9808_ADDR: case MCP9808_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2); registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
if (registerValue == 0x0400) { if (registerValue == 0x0400) {

View File

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

View File

@@ -7,20 +7,22 @@
#include "ubx.h" #include "ubx.h"
#ifdef ARCH_PORTDUINO #ifdef ARCH_PORTDUINO
#include "PortduinoGlue.h"
#include "meshUtils.h" #include "meshUtils.h"
#include <ctime>
#endif #endif
#ifndef GPS_RESET_MODE #ifndef GPS_RESET_MODE
#define GPS_RESET_MODE HIGH #define GPS_RESET_MODE HIGH
#endif #endif
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_RASPBERRY_PI)
HardwareSerial *GPS::_serial_gps = &Serial1; HardwareSerial *GPS::_serial_gps = &Serial1;
#else #else
HardwareSerial *GPS::_serial_gps = NULL; HardwareSerial *GPS::_serial_gps = NULL;
#endif #endif
GPS *gps; GPS *gps = nullptr;
/// Multiple GPS instances might use the same serial port (in sequence), but we can /// Multiple GPS instances might use the same serial port (in sequence), but we can
/// only init that port once. /// only init that port once.
@@ -76,28 +78,25 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
while (millis() < startTimeout) { while (millis() < startTimeout) {
if (_serial_gps->available()) { if (_serial_gps->available()) {
b = _serial_gps->read(); b = _serial_gps->read();
#ifdef GPS_DEBUG
LOG_DEBUG("%02X", (char *)buffer);
#endif
buffer[bytesRead] = b; buffer[bytesRead] = b;
bytesRead++; bytesRead++;
if ((bytesRead == 767) || (b == '\r')) { if ((bytesRead == 767) || (b == '\r')) {
if (strnstr((char *)buffer, message, bytesRead) != nullptr) { if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
#ifdef GPS_DEBUG #ifdef GPS_DEBUG
buffer[bytesRead] = '\0'; LOG_DEBUG("\r");
LOG_DEBUG("%s\r", (char *)buffer);
#endif #endif
return GNSS_RESPONSE_OK; return GNSS_RESPONSE_OK;
} else { } else {
#ifdef GPS_DEBUG
buffer[bytesRead] = '\0';
LOG_INFO("Bytes read:%s\n", (char *)buffer);
#endif
bytesRead = 0; bytesRead = 0;
} }
} }
} }
} }
#ifdef GPS_DEBUG #ifdef GPS_DEBUG
buffer[bytesRead] = '\0'; LOG_DEBUG("\n");
LOG_INFO("Bytes read:%s\n", (char *)buffer);
#endif #endif
return GNSS_RESPONSE_NONE; return GNSS_RESPONSE_NONE;
} }
@@ -252,10 +251,32 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
bool GPS::setup() bool GPS::setup()
{ {
int msglen = 0; int msglen = 0;
bool isProblematicGPS = false;
if (!didSerialInit) { if (!didSerialInit) {
#if !defined(GPS_UC6580) #if !defined(GPS_UC6580)
if (tx_gpio) { #ifdef HAS_PMU
// The T-Beam 1.2 has issues with the GPS
if (HW_VENDOR == meshtastic_HardwareModel_TBEAM && PMU->getChipModel() == XPOWERS_AXP2101) {
gnssModel = GNSS_MODEL_UBLOX;
isProblematicGPS = true;
}
#endif
#if defined(RAK4630) && defined(PIN_3V3_EN)
// If we are using the RAK4630 and we have no other peripherals on the I2C bus or module interest in 3V3_S,
// then we can safely set en_gpio turn off power to 3V3 (IO2) to hard sleep the GPS
if (rtc_found.port == ScanI2C::DeviceType::NONE && rgb_found.type == ScanI2C::DeviceType::NONE &&
accelerometer_found.port == ScanI2C::DeviceType::NONE && !moduleConfig.detection_sensor.enabled &&
!moduleConfig.telemetry.air_quality_enabled && !moduleConfig.telemetry.environment_measurement_enabled &&
config.power.device_battery_ina_address == 0 && en_gpio == 0) {
LOG_DEBUG("Since no problematic peripherals or interested modules were found, setting power save GPS_EN to pin %i\n",
PIN_3V3_EN);
en_gpio = PIN_3V3_EN;
}
#endif
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]); LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]);
gnssModel = probe(serialSpeeds[speedSelect]); gnssModel = probe(serialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) { if (gnssModel == GNSS_MODEL_UNKNOWN) {
@@ -272,7 +293,7 @@ bool GPS::setup()
gnssModel = GNSS_MODEL_UNKNOWN; gnssModel = GNSS_MODEL_UNKNOWN;
} }
#else #else
gnssModel = GNSS_MODEL_UC6850; gnssModel = GNSS_MODEL_UC6580;
#endif #endif
if (gnssModel == GNSS_MODEL_MTK) { if (gnssModel == GNSS_MODEL_MTK) {
@@ -290,11 +311,23 @@ bool GPS::setup()
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
_serial_gps->write("$PCAS11,3*1E\r\n"); _serial_gps->write("$PCAS11,3*1E\r\n");
delay(250); delay(250);
} else if (gnssModel == GNSS_MODEL_UC6850) { } else if (gnssModel == GNSS_MODEL_UC6580) {
// The Unicore UC6580 can use a lot of sat systems, enable it to
// use GPS + GLONASS // use GPS L1 & L5 + BDS B1I & B2a + GLONASS L1 + GALILEO E1 & E5a + SBAS
_serial_gps->write("$CFGSYS,h15\r\n"); // This will reset the receiver, so wait a bit afterwards
// The paranoid will wait for the OK*04 confirmation response after each command.
_serial_gps->write("$CFGSYS,h25155\r\n");
delay(750);
// Must be done after the CFGSYS command
// Turn off GSV messages, we don't really care about which and where the sats are, maybe someday.
_serial_gps->write("$CFGMSG,0,3,0\r\n");
delay(250); delay(250);
// Turn off NOTICE __TXT messages, these may provide Unicore some info but we don't care.
_serial_gps->write("$CFGMSG,6,0,0\r\n");
delay(250);
_serial_gps->write("$CFGMSG,6,1,0\r\n");
delay(250);
} else if (gnssModel == GNSS_MODEL_UBLOX) { } else if (gnssModel == GNSS_MODEL_UBLOX) {
// Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command) // Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command)
// We need set it because by default it is GPS only, and we want to use GLONASS too // We need set it because by default it is GPS only, and we want to use GLONASS too
@@ -390,32 +423,36 @@ bool GPS::setup()
LOG_WARN("Unable to enable powersaving for GPS.\n"); LOG_WARN("Unable to enable powersaving for GPS.\n");
} }
} else { } else {
if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode has only been tested on this hardware if (!(isProblematicGPS)) {
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM); if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode has only been tested on this hardware
_serial_gps->write(UBXscratch, msglen); msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM);
if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) { _serial_gps->write(UBXscratch, msglen);
LOG_WARN("Unable to enable powersaving mode for GPS.\n"); if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
} LOG_WARN("Unable to enable powersaving mode for GPS.\n");
msglen = makeUBXPacket(0x06, 0x3B, 44, _message_CFG_PM2); }
_serial_gps->write(UBXscratch, msglen); msglen = makeUBXPacket(0x06, 0x3B, 44, _message_CFG_PM2);
if (getACK(0x06, 0x3B, 300) != GNSS_RESPONSE_OK) { _serial_gps->write(UBXscratch, msglen);
LOG_WARN("Unable to enable powersaving details for GPS.\n"); if (getACK(0x06, 0x3B, 300) != GNSS_RESPONSE_OK) {
} LOG_WARN("Unable to enable powersaving details for GPS.\n");
} else { }
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO); } else {
_serial_gps->write(UBXscratch, msglen); msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO);
if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) { _serial_gps->write(UBXscratch, msglen);
LOG_WARN("Unable to enable powersaving ECO mode for GPS.\n"); if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving ECO mode for GPS.\n");
}
} }
} }
} }
// The T-beam 1.2 has issues.
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE); if (!(isProblematicGPS)) {
_serial_gps->write(UBXscratch, msglen); msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) { _serial_gps->write(UBXscratch, msglen);
LOG_WARN("Unable to save GNSS module configuration.\n"); if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) {
} else { LOG_WARN("Unable to save GNSS module configuration.\n");
LOG_INFO("GNSS module configuration saved!\n"); } else {
LOG_INFO("GNSS module configuration saved!\n");
}
} }
} }
didSerialInit = true; didSerialInit = true;
@@ -423,6 +460,7 @@ bool GPS::setup()
notifyDeepSleepObserver.observe(&notifyDeepSleep); notifyDeepSleepObserver.observe(&notifyDeepSleep);
notifyGPSSleepObserver.observe(&notifyGPSSleep); notifyGPSSleepObserver.observe(&notifyGPSSleep);
return true; return true;
} }
@@ -433,7 +471,7 @@ GPS::~GPS()
notifyGPSSleepObserver.observe(&notifyGPSSleep); notifyGPSSleepObserver.observe(&notifyGPSSleep);
} }
void GPS::setGPSPower(bool on, bool standbyOnly) void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime)
{ {
LOG_INFO("Setting GPS power=%d\n", on); LOG_INFO("Setting GPS power=%d\n", on);
if (on) { if (on) {
@@ -469,20 +507,24 @@ void GPS::setGPSPower(bool on, bool standbyOnly)
#ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76K and clones #ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76K and clones
if (on) { if (on) {
LOG_INFO("Waking GPS"); LOG_INFO("Waking GPS");
digitalWrite(PIN_GPS_STANDBY, 1);
pinMode(PIN_GPS_STANDBY, OUTPUT); pinMode(PIN_GPS_STANDBY, OUTPUT);
digitalWrite(PIN_GPS_STANDBY, 1);
return; return;
} else { } else {
LOG_INFO("GPS entering sleep"); LOG_INFO("GPS entering sleep");
// notifyGPSSleep.notifyObservers(NULL); // notifyGPSSleep.notifyObservers(NULL);
digitalWrite(PIN_GPS_STANDBY, 0);
pinMode(PIN_GPS_STANDBY, OUTPUT); pinMode(PIN_GPS_STANDBY, OUTPUT);
digitalWrite(PIN_GPS_STANDBY, 0);
return; return;
} }
#endif #endif
if (!on) { if (!on) {
if (gnssModel == GNSS_MODEL_UBLOX) { if (gnssModel == GNSS_MODEL_UBLOX) {
uint8_t msglen; uint8_t msglen;
LOG_DEBUG("Sleep Time: %i\n", sleepTime);
for (int i = 0; i < 4; i++) {
gps->_message_PMREQ[0 + i] = sleepTime >> (i * 8); // Encode the sleep time in millis into the packet
}
msglen = gps->makeUBXPacket(0x02, 0x41, 0x08, gps->_message_PMREQ); msglen = gps->makeUBXPacket(0x02, 0x41, 0x08, gps->_message_PMREQ);
gps->_serial_gps->write(gps->UBXscratch, msglen); gps->_serial_gps->write(gps->UBXscratch, msglen);
} }
@@ -514,7 +556,7 @@ void GPS::setAwake(bool on)
LOG_DEBUG("WANT GPS=%d\n", on); LOG_DEBUG("WANT GPS=%d\n", on);
isAwake = on; isAwake = on;
if (!enabled) { // short circuit if the user has disabled GPS if (!enabled) { // short circuit if the user has disabled GPS
setGPSPower(false, false); setGPSPower(false, false, 0);
return; return;
} }
@@ -532,16 +574,21 @@ void GPS::setAwake(bool on)
} }
if ((int32_t)getSleepTime() - averageLockTime > if ((int32_t)getSleepTime() - averageLockTime >
15 * 60 * 1000) { // 15 minutes is probably long enough to make a complete poweroff worth it. 15 * 60 * 1000) { // 15 minutes is probably long enough to make a complete poweroff worth it.
setGPSPower(on, false); setGPSPower(on, false, getSleepTime() - averageLockTime);
return;
} else if ((int32_t)getSleepTime() - averageLockTime > 10000) { // 10 seconds is enough for standby } else if ((int32_t)getSleepTime() - averageLockTime > 10000) { // 10 seconds is enough for standby
#ifdef GPS_UC6580 #ifdef GPS_UC6580
setGPSPower(on, false); setGPSPower(on, false, getSleepTime() - averageLockTime);
#else #else
setGPSPower(on, true); setGPSPower(on, true, getSleepTime() - averageLockTime);
#endif #endif
} else if (averageLockTime > 20000) { return;
}
if (averageLockTime > 20000) {
averageLockTime -= 1000; // eventually want to sleep again. averageLockTime -= 1000; // eventually want to sleep again.
} }
if (on)
setGPSPower(true, true, 0); // make sure we don't have a fallthrough where GPS is stuck off
} }
} }
@@ -549,11 +596,12 @@ void GPS::setAwake(bool on)
*/ */
uint32_t GPS::getWakeTime() const uint32_t GPS::getWakeTime() const
{ {
uint32_t t = config.position.gps_attempt_time; uint32_t t = config.position.position_broadcast_secs;
if (t == UINT32_MAX) if (t == UINT32_MAX)
return t; // already maxint return t; // already maxint
return t * 1000;
return getConfiguredOrDefaultMs(t, default_broadcast_interval_secs);
} }
/** Get how long we should sleep between aqusition attempts in msecs /** Get how long we should sleep between aqusition attempts in msecs
@@ -598,7 +646,7 @@ int32_t GPS::runOnce()
return 2000; // Setup failed, re-run in two seconds return 2000; // Setup failed, re-run in two seconds
// We have now loaded our saved preferences from flash // We have now loaded our saved preferences from flash
if (config.position.gps_enabled == false && config.position.fixed_position == false) { if (config.position.gps_enabled == false) {
return disable(); return disable();
} }
// ONCE we will factory reset the GPS for bug #327 // ONCE we will factory reset the GPS for bug #327
@@ -631,6 +679,11 @@ int32_t GPS::runOnce()
} }
} }
} }
// At least one GPS has a bad habit of losing its mind from time to time
if (rebootsSeen > 2) {
rebootsSeen = 0;
gps->factoryReset();
}
// If we are overdue for an update, turn on the GPS and at least publish the current status // If we are overdue for an update, turn on the GPS and at least publish the current status
uint32_t now = millis(); uint32_t now = millis();
@@ -685,8 +738,8 @@ int32_t GPS::runOnce()
// If state has changed do a publish // If state has changed do a publish
publishUpdate(); publishUpdate();
if (config.position.gps_enabled == false) // This should trigger if GPS is disabled but fixed_position is true if (config.position.fixed_position == true && hasValidLocation)
return disable(); return disable(); // This should trigger when we have a fixed position, and get that first position
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms // 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake. // if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
@@ -870,6 +923,10 @@ GPS *GPS::createGps()
#if defined(PIN_GPS_EN) #if defined(PIN_GPS_EN)
if (!_en_gpio) if (!_en_gpio)
_en_gpio = PIN_GPS_EN; _en_gpio = PIN_GPS_EN;
#endif
#ifdef ARCH_RASPBERRY_PI
if (!settingsMap[has_gps])
return nullptr;
#endif #endif
if (!_rx_gpio || !_serial_gps) // Configured to have no GPS at all if (!_rx_gpio || !_serial_gps) // Configured to have no GPS at all
return nullptr; return nullptr;
@@ -881,8 +938,8 @@ GPS *GPS::createGps()
if (_en_gpio != 0) { if (_en_gpio != 0) {
LOG_DEBUG("Setting %d to output.\n", _en_gpio); LOG_DEBUG("Setting %d to output.\n", _en_gpio);
digitalWrite(_en_gpio, !GPS_EN_ACTIVE);
pinMode(_en_gpio, OUTPUT); pinMode(_en_gpio, OUTPUT);
digitalWrite(_en_gpio, !GPS_EN_ACTIVE);
} }
#ifdef PIN_GPS_PPS #ifdef PIN_GPS_PPS
@@ -899,13 +956,11 @@ GPS *GPS::createGps()
LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n"); LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n");
#endif #endif
if (config.position.gps_enabled) { new_gps->setGPSPower(true, false, 0);
new_gps->setGPSPower(true, false);
}
#ifdef PIN_GPS_RESET #ifdef PIN_GPS_RESET
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
pinMode(PIN_GPS_RESET, OUTPUT); pinMode(PIN_GPS_RESET, OUTPUT);
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
delay(10); delay(10);
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE); digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
#endif #endif
@@ -950,17 +1005,44 @@ bool GPS::factoryReset()
{ {
#ifdef PIN_GPS_REINIT #ifdef PIN_GPS_REINIT
// The L76K GNSS on the T-Echo requires the RESET pin to be pulled LOW // 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); pinMode(PIN_GPS_REINIT, OUTPUT);
digitalWrite(PIN_GPS_REINIT, 0);
delay(150); // The L76K datasheet calls for at least 100MS delay delay(150); // The L76K datasheet calls for at least 100MS delay
digitalWrite(PIN_GPS_REINIT, 1); digitalWrite(PIN_GPS_REINIT, 1);
#endif #endif
// send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX. if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) {
// Factory Reset byte _message_reset1[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xA2};
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E}; _serial_gps->write(_message_reset1, sizeof(_message_reset1));
_serial_gps->write(_message_reset, sizeof(_message_reset)); if (getACK(0x05, 0x01, 10000)) {
LOG_INFO("Get ack success!\n");
}
delay(100);
byte _message_reset2[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1B, 0xA1};
_serial_gps->write(_message_reset2, sizeof(_message_reset2));
if (getACK(0x05, 0x01, 10000)) {
LOG_INFO("Get ack success!\n");
}
delay(100);
byte _message_reset3[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1D, 0xB3};
_serial_gps->write(_message_reset3, sizeof(_message_reset3));
if (getACK(0x05, 0x01, 10000)) {
LOG_INFO("Get ack success!\n");
}
// Reset device ram to COLDSTART state
// byte _message_CFG_RST_COLDSTART[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B};
// _serial_gps->write(_message_CFG_RST_COLDSTART, sizeof(_message_CFG_RST_COLDSTART));
// delay(1000);
} else {
// 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); delay(1000);
return true; return true;
} }
@@ -1157,6 +1239,7 @@ bool GPS::hasFlow()
bool GPS::whileIdle() bool GPS::whileIdle()
{ {
int charsInBuf = 0;
bool isValid = false; bool isValid = false;
if (!isAwake) { if (!isAwake) {
clearBuffer(); clearBuffer();
@@ -1173,10 +1256,20 @@ bool GPS::whileIdle()
// First consume any chars that have piled up at the receiver // First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) { while (_serial_gps->available() > 0) {
int c = _serial_gps->read(); int c = _serial_gps->read();
// LOG_DEBUG("%c", c); UBXscratch[charsInBuf] = c;
#ifdef GPS_DEBUG
LOG_DEBUG("%c", c);
#endif
isValid |= reader.encode(c); isValid |= reader.encode(c);
if (charsInBuf > sizeof(UBXscratch) - 10 || c == '\r') {
if (strnstr((char *)UBXscratch, "$GPTXT,01,01,02,u-blox ag - www.u-blox.com*50", charsInBuf)) {
rebootsSeen++;
}
charsInBuf = 0;
} else {
charsInBuf++;
}
} }
return isValid; return isValid;
} }
void GPS::enable() void GPS::enable()
@@ -1193,4 +1286,4 @@ int32_t GPS::disable()
setAwake(false); setAwake(false);
return INT32_MAX; return INT32_MAX;
} }

View File

@@ -23,7 +23,7 @@ struct uBloxGnssModelInfo {
typedef enum { typedef enum {
GNSS_MODEL_MTK, GNSS_MODEL_MTK,
GNSS_MODEL_UBLOX, GNSS_MODEL_UBLOX,
GNSS_MODEL_UC6850, GNSS_MODEL_UC6580,
GNSS_MODEL_UNKNOWN, GNSS_MODEL_UNKNOWN,
} GnssModel_t; } GnssModel_t;
@@ -70,7 +70,7 @@ class GPS : private concurrency::OSThread
/** /**
* hasValidLocation - indicates that the position variables contain a complete * hasValidLocation - indicates that the position variables contain a complete
* GPS location, valid and fresh (< gps_update_interval + gps_attempt_time) * GPS location, valid and fresh (< gps_update_interval + position_broadcast_secs)
*/ */
bool hasValidLocation = false; // default to false, until we complete our first read bool hasValidLocation = false; // default to false, until we complete our first read
@@ -94,7 +94,7 @@ class GPS : private concurrency::OSThread
/** If !NULL we will use this serial port to construct our GPS */ /** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps; static HardwareSerial *_serial_gps;
static const uint8_t _message_PMREQ[]; static uint8_t _message_PMREQ[];
static const uint8_t _message_CFG_RXM_PSM[]; static const uint8_t _message_CFG_RXM_PSM[];
static const uint8_t _message_CFG_RXM_ECO[]; static const uint8_t _message_CFG_RXM_ECO[];
static const uint8_t _message_CFG_PM2[]; static const uint8_t _message_CFG_PM2[];
@@ -132,7 +132,7 @@ class GPS : private concurrency::OSThread
// Disable the thread // Disable the thread
int32_t disable() override; int32_t disable() override;
void setGPSPower(bool on, bool standbyOnly); void setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime);
/// Returns true if we have acquired GPS lock. /// Returns true if we have acquired GPS lock.
virtual bool hasLock(); virtual bool hasLock();
@@ -154,6 +154,8 @@ class GPS : private concurrency::OSThread
// scratch space for creating ublox packets // scratch space for creating ublox packets
uint8_t UBXscratch[250] = {0}; uint8_t UBXscratch[250] = {0};
int rebootsSeen = 0;
int getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID, uint32_t waitMillis); 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(uint8_t c, uint8_t i, uint32_t waitMillis);
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis); GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);

View File

@@ -152,7 +152,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
#endif #endif
// nrf52 doesn't have a readable RTC (yet - software not written) // nrf52 doesn't have a readable RTC (yet - software not written)
#ifdef HAS_RTC #if HAS_RTC
readFromRTC(); readFromRTC();
#endif #endif
@@ -208,4 +208,4 @@ uint32_t getTime()
uint32_t getValidTime(RTCQuality minQuality) uint32_t getValidTime(RTCQuality minQuality)
{ {
return (currentQuality >= minQuality) ? getTime() : 0; return (currentQuality >= minQuality) ? getTime() : 0;
} }

View File

@@ -1,4 +1,4 @@
const uint8_t GPS::_message_PMREQ[] PROGMEM = { uint8_t GPS::_message_PMREQ[] PROGMEM = {
0x00, 0x00, // 4 bytes duration of request task 0x00, 0x00, // 4 bytes duration of request task
0x00, 0x00, // (milliseconds) 0x00, 0x00, // (milliseconds)
0x02, 0x00, // Task flag bitfield 0x02, 0x00, // Task flag bitfield
@@ -17,7 +17,7 @@ const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = {
const uint8_t GPS::_message_CFG_PM2[] PROGMEM = { const uint8_t GPS::_message_CFG_PM2[] PROGMEM = {
0x01, 0x06, 0x00, 0x00, // version, Reserved 0x01, 0x06, 0x00, 0x00, // version, Reserved
0x0e, 0x81, 0x42, 0x01, // flags 0x0E, 0x81, 0x43, 0x01, // flags
0xE8, 0x03, 0x00, 0x00, // update period 1000 ms 0xE8, 0x03, 0x00, 0x00, // update period 1000 ms
0x10, 0x27, 0x00, 0x00, // search period 10s 0x10, 0x27, 0x00, 0x00, // search period 10s
0x00, 0x00, 0x00, 0x00, // Grod offset 0 0x00, 0x00, 0x00, 0x00, // Grod offset 0
@@ -189,4 +189,4 @@ const uint8_t GPS::_message_SAVE[] = {
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections 0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded 0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x0F // deviceMask: BBR, Flash, EEPROM, and SPI Flash 0x0F // deviceMask: BBR, Flash, EEPROM, and SPI Flash
}; };

View File

@@ -7,9 +7,9 @@
#include "main.h" #include "main.h"
#include <SPI.h> #include <SPI.h>
// #ifdef HELTEC_WIRELESS_PAPER #ifdef HELTEC_WIRELESS_PAPER
// SPIClass *hspi = NULL; SPIClass *hspi = NULL;
// #endif #endif
#define COLORED GxEPD_BLACK #define COLORED GxEPD_BLACK
#define UNCOLORED GxEPD_WHITE #define UNCOLORED GxEPD_WHITE
@@ -46,8 +46,8 @@
#define TECHO_DISPLAY_MODEL GxEPD2_154_M09 #define TECHO_DISPLAY_MODEL GxEPD2_154_M09
#elif defined(HELTEC_WIRELESS_PAPER) #elif defined(HELTEC_WIRELESS_PAPER)
//#define TECHO_DISPLAY_MODEL GxEPD2_213_T5D // #define TECHO_DISPLAY_MODEL GxEPD2_213_T5D
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN #define TECHO_DISPLAY_MODEL GxEPD2_213_FC1
#endif #endif
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay; GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
@@ -71,7 +71,7 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY
// setGeometry(GEOMETRY_RAWMODE, 200, 200); // setGeometry(GEOMETRY_RAWMODE, 200, 200);
#elif defined(HELTEC_WIRELESS_PAPER) #elif defined(HELTEC_WIRELESS_PAPER)
// setGeometry(GEOMETRY_RAWMODE, 212, 104); // GxEPD2_213_BN - 2.13 inch b/w 250x122
setGeometry(GEOMETRY_RAWMODE, 250, 122); setGeometry(GEOMETRY_RAWMODE, 250, 122);
#elif defined(MAKERPYTHON) #elif defined(MAKERPYTHON)
// GxEPD2_290_T5D // GxEPD2_290_T5D
@@ -119,7 +119,6 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK); // tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint32_t y = 0; y < displayHeight; y++) { for (uint32_t y = 0; y < displayHeight; y++) {
for (uint32_t x = 0; x < displayWidth; x++) { for (uint32_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient // get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient
auto b = buffer[x + (y / 8) * displayWidth]; auto b = buffer[x + (y / 8) * displayWidth];
auto isset = b & (1 << (y & 7)); auto isset = b & (1 << (y & 7));
@@ -148,7 +147,8 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
#elif defined(PCA10059) || defined(M5_COREINK) #elif defined(PCA10059) || defined(M5_COREINK)
adafruitDisplay->nextPage(); adafruitDisplay->nextPage();
#elif defined(HELTEC_WIRELESS_PAPER)
adafruitDisplay->nextPage();
#elif defined(PRIVATE_HW) || defined(my) #elif defined(PRIVATE_HW) || defined(my)
adafruitDisplay->nextPage(); adafruitDisplay->nextPage();
@@ -193,14 +193,14 @@ bool EInkDisplay::connect()
LOG_INFO("Doing EInk init\n"); LOG_INFO("Doing EInk init\n");
#ifdef PIN_EINK_PWR_ON #ifdef PIN_EINK_PWR_ON
digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
pinMode(PIN_EINK_PWR_ON, OUTPUT); pinMode(PIN_EINK_PWR_ON, OUTPUT);
digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
#endif #endif
#ifdef PIN_EINK_EN #ifdef PIN_EINK_EN
// backlight power, HIGH is backlight on, LOW is off // backlight power, HIGH is backlight on, LOW is off
digitalWrite(PIN_EINK_EN, LOW);
pinMode(PIN_EINK_EN, OUTPUT); pinMode(PIN_EINK_EN, OUTPUT);
digitalWrite(PIN_EINK_EN, LOW);
#endif #endif
#if defined(TTGO_T_ECHO) #if defined(TTGO_T_ECHO)
@@ -231,13 +231,16 @@ bool EInkDisplay::connect()
} }
#elif defined(HELTEC_WIRELESS_PAPER) #elif defined(HELTEC_WIRELESS_PAPER)
{ {
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY); hspi = new SPIClass(HSPI);
hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS
delay(100);
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW);
delay(100);
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *hspi);
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel); adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
// hspi = new SPIClass(HSPI); adafruitDisplay->init();
// hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS
adafruitDisplay->init(115200, true, 10, false, SPI, SPISettings(6000000, MSBFIRST, SPI_MODE0));
adafruitDisplay->setRotation(3); adafruitDisplay->setRotation(3);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
} }
#elif defined(PCA10059) #elif defined(PCA10059)
{ {

View File

@@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#if HAS_SCREEN #if HAS_SCREEN
#include <OLEDDisplay.h> #include <OLEDDisplay.h>
#include "DisplayFormatters.h"
#include "GPS.h" #include "GPS.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
@@ -42,12 +43,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
#if HAS_WIFI && !defined(ARCH_RASPBERRY_PI)
#include "mesh/wifi/WiFiAPClient.h"
#endif
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "mesh/http/WiFiAPClient.h"
#include "modules/esp32/StoreForwardModule.h" #include "modules/esp32/StoreForwardModule.h"
#endif #endif
#if ARCH_RASPBERRY_PI
#include "platform/portduino/PortduinoGlue.h"
#endif
#ifdef OLED_RU #ifdef OLED_RU
#include "fonts/OLEDDisplayFontsRU.h" #include "fonts/OLEDDisplayFontsRU.h"
#endif #endif
@@ -160,17 +168,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 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); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
screen->forceDisplay(); screen->forceDisplay();
// FIXME - draw serial # somewhere? // 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) static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
// draw an xbm image. // draw an xbm image.
@@ -220,6 +220,28 @@ static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
drawOEMIconScreen(region, display, state, x, y); 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 // Used on boot when a certificate is being created
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
@@ -320,22 +342,6 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
display->drawString(x_offset + x, y_offset + y, deviceName); 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) static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
display->setTextAlignment(TEXT_ALIGN_CENTER); display->setTextAlignment(TEXT_ALIGN_CENTER);
@@ -906,28 +912,44 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
drawColumns(display, x, y, fields); 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) 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), : 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),
ui(&dispdev)
{ {
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
dispdev = new SH1106Wire(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
#elif defined(USE_SSD1306)
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014)
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
#elif defined(USE_EINK)
dispdev = new EInkDisplay(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
#elif defined(USE_ST7567)
dispdev = new ST7567Wire(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
#elif ARCH_RASPBERRY_PI
if (settingsMap[displayPanel] == st7789) {
LOG_DEBUG("Making TFTDisplay!\n");
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
} else {
dispdev = new AutoOLEDWire(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
isAUTOOled = true;
}
#else
dispdev = new AutoOLEDWire(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
isAUTOOled = true;
#endif
ui = new OLEDDisplayUi(dispdev);
cmdQueue.setReader(this); cmdQueue.setReader(this);
} }
// #endif
/** /**
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just * 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 * poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
@@ -937,8 +959,8 @@ void Screen::doDeepSleep()
#ifdef USE_EINK #ifdef USE_EINK
static FrameCallback sleepFrames[] = {drawSleepScreen}; static FrameCallback sleepFrames[] = {drawSleepScreen};
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]); static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
ui.setFrames(sleepFrames, sleepFrameCount); ui->setFrames(sleepFrames, sleepFrameCount);
ui.update(); ui->update();
#endif #endif
setOn(false); setOn(false);
} }
@@ -954,14 +976,16 @@ void Screen::handleSetOn(bool on)
#ifdef T_WATCH_S3 #ifdef T_WATCH_S3
PMU->enablePowerOutput(XPOWERS_ALDO2); PMU->enablePowerOutput(XPOWERS_ALDO2);
#endif #endif
dispdev.displayOn(); #if !ARCH_RASPBERRY_PI
dispdev.displayOn(); dispdev->displayOn();
#endif
dispdev->displayOn();
enabled = true; enabled = true;
setInterval(0); // Draw ASAP setInterval(0); // Draw ASAP
runASAP = true; runASAP = true;
} else { } else {
LOG_INFO("Turning off screen\n"); LOG_INFO("Turning off screen\n");
dispdev.displayOff(); dispdev->displayOff();
#ifdef T_WATCH_S3 #ifdef T_WATCH_S3
PMU->disablePowerOutput(XPOWERS_ALDO2); PMU->disablePowerOutput(XPOWERS_ALDO2);
#endif #endif
@@ -978,32 +1002,33 @@ void Screen::setup()
useDisplay = true; useDisplay = true;
#ifdef AutoOLEDWire_h #ifdef AutoOLEDWire_h
dispdev.setDetected(model); if (isAUTOOled)
static_cast<AutoOLEDWire *>(dispdev)->setDetected(model);
#endif #endif
#ifdef USE_SH1107_128_64 #ifdef USE_SH1107_128_64
dispdev.setSubtype(7); static_cast<SH1106Wire *>(dispdev)->setSubtype(7);
#endif #endif
// Initialising the UI will init the display too. // Initialising the UI will init the display too.
ui.init(); ui->init();
displayWidth = dispdev.width(); displayWidth = dispdev->width();
displayHeight = dispdev.height(); displayHeight = dispdev->height();
ui.setTimePerTransition(0); ui->setTimePerTransition(0);
ui.setIndicatorPosition(BOTTOM); ui->setIndicatorPosition(BOTTOM);
// Defines where the first frame is located in the bar. // Defines where the first frame is located in the bar.
ui.setIndicatorDirection(LEFT_RIGHT); ui->setIndicatorDirection(LEFT_RIGHT);
ui.setFrameAnimation(SLIDE_LEFT); ui->setFrameAnimation(SLIDE_LEFT);
// Don't show the page swipe dots while in boot screen. // Don't show the page swipe dots while in boot screen.
ui.disableAllIndicators(); ui->disableAllIndicators();
// Store a pointer to Screen so we can get to it from static functions. // Store a pointer to Screen so we can get to it from static functions.
ui.getUiState()->userData = this; ui->getUiState()->userData = this;
// Set the utf8 conversion function // Set the utf8 conversion function
dispdev.setFontTableLookupFunction(customFontTableLookup); dispdev->setFontTableLookupFunction(customFontTableLookup);
if (strlen(oemStore.oem_text) > 0) if (strlen(oemStore.oem_text) > 0)
logo_timeout *= 2; logo_timeout *= 2;
@@ -1011,23 +1036,23 @@ void Screen::setup()
// Add frames. // Add frames.
static FrameCallback bootFrames[] = {drawBootScreen}; static FrameCallback bootFrames[] = {drawBootScreen};
static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]); static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]);
ui.setFrames(bootFrames, bootFrameCount); ui->setFrames(bootFrames, bootFrameCount);
// No overlays. // No overlays.
ui.setOverlays(nullptr, 0); ui->setOverlays(nullptr, 0);
// Require presses to switch between frames. // Require presses to switch between frames.
ui.disableAutoTransition(); ui->disableAutoTransition();
// Set up a log buffer with 3 lines, 32 chars each. // Set up a log buffer with 3 lines, 32 chars each.
dispdev.setLogBuffer(3, 32); dispdev->setLogBuffer(3, 32);
#ifdef SCREEN_MIRROR #ifdef SCREEN_MIRROR
dispdev.mirrorScreen(); dispdev->mirrorScreen();
#else #else
// Standard behaviour is to FLIP the screen (needed on T-Beam). If this config item is set, unflip it, and thereby logically // Standard behaviour is to FLIP the screen (needed on T-Beam). If this config item is set, unflip it, and thereby logically
// flip it. If you have a headache now, you're welcome. // flip it. If you have a headache now, you're welcome.
if (!config.display.flip_screen) { if (!config.display.flip_screen) {
dispdev.flipScreenVertically(); dispdev->flipScreenVertically();
} }
#endif #endif
@@ -1035,20 +1060,30 @@ void Screen::setup()
uint8_t dmac[6]; uint8_t dmac[6];
getMacAddr(dmac); getMacAddr(dmac);
snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]); snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]);
#if ARCH_RASPBERRY_PI
handleSetOn(false); // force clean init
#endif
// Turn on the display. // Turn on the display.
handleSetOn(true); handleSetOn(true);
// On some ssd1306 clones, the first draw command is discarded, so draw it // On some ssd1306 clones, the first draw command is discarded, so draw it
// twice initially. Skip this for EINK Displays to save a few seconds during boot // twice initially. Skip this for EINK Displays to save a few seconds during boot
ui.update(); ui->update();
#ifndef USE_EINK #ifndef USE_EINK
ui.update(); ui->update();
#endif #endif
serialSinceMsec = millis(); serialSinceMsec = millis();
#if HAS_TOUCHSCREEN #if ARCH_RASPBERRY_PI
touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch); if (settingsMap[touchscreenModule]) {
touchScreenImpl1 =
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
touchScreenImpl1->init();
}
#elif HAS_TOUCHSCREEN
touchScreenImpl1 =
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
touchScreenImpl1->init(); touchScreenImpl1->init();
#endif #endif
@@ -1069,7 +1104,7 @@ void Screen::forceDisplay()
{ {
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup. // Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
#ifdef USE_EINK #ifdef USE_EINK
dispdev.forceDisplay(); static_cast<EInkDisplay *>(dispdev)->forceDisplay();
#endif #endif
} }
@@ -1100,10 +1135,10 @@ int32_t Screen::runOnce()
// Change frames. // Change frames.
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen}; static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]); static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
ui.setFrames(bootOEMFrames, bootOEMFrameCount); ui->setFrames(bootOEMFrames, bootOEMFrameCount);
ui.update(); ui->update();
#ifndef USE_EINK #ifndef USE_EINK
ui.update(); ui->update();
#endif #endif
showingOEMBootScreen = false; showingOEMBootScreen = false;
} }
@@ -1176,16 +1211,16 @@ int32_t Screen::runOnce()
// this must be before the frameState == FIXED check, because we always // this must be before the frameState == FIXED check, because we always
// want to draw at least one FIXED frame before doing forceDisplay // want to draw at least one FIXED frame before doing forceDisplay
ui.update(); ui->update();
// Switch to a low framerate (to save CPU) when we are not in transition // Switch to a low framerate (to save CPU) when we are not in transition
// but we should only call setTargetFPS when framestate changes, because // but we should only call setTargetFPS when framestate changes, because
// otherwise that breaks animations. // otherwise that breaks animations.
if (targetFramerate != IDLE_FRAMERATE && ui.getUiState()->frameState == FIXED) { if (targetFramerate != IDLE_FRAMERATE && ui->getUiState()->frameState == FIXED) {
// oldFrameState = ui.getUiState()->frameState; // oldFrameState = ui->getUiState()->frameState;
targetFramerate = IDLE_FRAMERATE; targetFramerate = IDLE_FRAMERATE;
ui.setTargetFPS(targetFramerate); ui->setTargetFPS(targetFramerate);
forceDisplay(); forceDisplay();
} }
@@ -1201,7 +1236,7 @@ int32_t Screen::runOnce()
} }
// LOG_DEBUG("want fps %d, fixed=%d\n", targetFramerate, // LOG_DEBUG("want fps %d, fixed=%d\n", targetFramerate,
// ui.getUiState()->frameState); If we are scrolling we need to be called // ui->getUiState()->frameState); If we are scrolling we need to be called
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice // soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
// as fast as we really need so that any rounding errors still result with // as fast as we really need so that any rounding errors still result with
// the correct framerate // the correct framerate
@@ -1233,8 +1268,8 @@ void Screen::setSSLFrames()
if (address_found.address) { if (address_found.address) {
// LOG_DEBUG("showing SSL frames\n"); // LOG_DEBUG("showing SSL frames\n");
static FrameCallback sslFrames[] = {drawSSLScreen}; static FrameCallback sslFrames[] = {drawSSLScreen};
ui.setFrames(sslFrames, 1); ui->setFrames(sslFrames, 1);
ui.update(); ui->update();
} }
} }
@@ -1244,11 +1279,8 @@ void Screen::setWelcomeFrames()
{ {
if (address_found.address) { if (address_found.address) {
// LOG_DEBUG("showing Welcome frames\n"); // LOG_DEBUG("showing Welcome frames\n");
ui.disableAllIndicators(); static FrameCallback frames[] = {drawWelcomeScreen};
setFrameImmediateDraw(frames);
static FrameCallback welcomeFrames[] = {drawWelcomeScreen};
ui.setFrames(welcomeFrames, 1);
ui.update();
} }
} }
@@ -1312,7 +1344,7 @@ void Screen::setFrames()
// call a method on debugInfoScreen object (for more details) // call a method on debugInfoScreen object (for more details)
normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline; normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
#ifdef ARCH_ESP32 #if HAS_WIFI && !defined(ARCH_RASPBERRY_PI)
if (isWifiAvailable()) { if (isWifiAvailable()) {
// call a method on debugInfoScreen object (for more details) // call a method on debugInfoScreen object (for more details)
normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline; normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline;
@@ -1321,8 +1353,8 @@ void Screen::setFrames()
LOG_DEBUG("Finished building frames. numframes: %d\n", numframes); LOG_DEBUG("Finished building frames. numframes: %d\n", numframes);
ui.setFrames(normalFrames, numframes); ui->setFrames(normalFrames, numframes);
ui.enableAllIndicators(); ui->enableAllIndicators();
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
// just changed) // just changed)
@@ -1335,12 +1367,15 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
LOG_DEBUG("showing bluetooth screen\n"); LOG_DEBUG("showing bluetooth screen\n");
showingNormalScreen = false; showingNormalScreen = false;
static FrameCallback btFrames[] = {drawFrameBluetooth}; static FrameCallback frames[] = {drawFrameBluetooth};
snprintf(btPIN, sizeof(btPIN), "%06u", pin); snprintf(btPIN, sizeof(btPIN), "%06u", pin);
setFrameImmediateDraw(frames);
}
ui.disableAllIndicators(); void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
ui.setFrames(btFrames, 1); {
ui->disableAllIndicators();
ui->setFrames(drawFrames, 1);
setFastFramerate(); setFastFramerate();
} }
@@ -1349,11 +1384,12 @@ void Screen::handleShutdownScreen()
LOG_DEBUG("showing shutdown screen\n"); LOG_DEBUG("showing shutdown screen\n");
showingNormalScreen = false; 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(); setFrameImmediateDraw(frames);
ui.setFrames(shutdownFrames, 1);
setFastFramerate();
} }
void Screen::handleRebootScreen() void Screen::handleRebootScreen()
@@ -1361,11 +1397,11 @@ void Screen::handleRebootScreen()
LOG_DEBUG("showing reboot screen\n"); LOG_DEBUG("showing reboot screen\n");
showingNormalScreen = false; showingNormalScreen = false;
static FrameCallback rebootFrames[] = {drawFrameReboot}; auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
drawFrameText(display, state, x, y, "Rebooting...");
ui.disableAllIndicators(); };
ui.setFrames(rebootFrames, 1); static FrameCallback frames[] = {frame};
setFastFramerate(); setFrameImmediateDraw(frames);
} }
void Screen::handleStartFirmwareUpdateScreen() void Screen::handleStartFirmwareUpdateScreen()
@@ -1373,28 +1409,25 @@ void Screen::handleStartFirmwareUpdateScreen()
LOG_DEBUG("showing firmware screen\n"); LOG_DEBUG("showing firmware screen\n");
showingNormalScreen = false; showingNormalScreen = false;
static FrameCallback btFrames[] = {drawFrameFirmware}; static FrameCallback frames[] = {drawFrameFirmware};
setFrameImmediateDraw(frames);
ui.disableAllIndicators();
ui.setFrames(btFrames, 1);
setFastFramerate();
} }
void Screen::blink() void Screen::blink()
{ {
setFastFramerate(); setFastFramerate();
uint8_t count = 10; uint8_t count = 10;
dispdev.setBrightness(254); dispdev->setBrightness(254);
while (count > 0) { while (count > 0) {
dispdev.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); dispdev->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
dispdev.display(); dispdev->display();
delay(50); delay(50);
dispdev.clear(); dispdev->clear();
dispdev.display(); dispdev->display();
delay(50); delay(50);
count = count - 1; count = count - 1;
} }
dispdev.setBrightness(brightness); dispdev->setBrightness(brightness);
} }
std::string Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds) std::string Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds)
@@ -1422,15 +1455,15 @@ void Screen::handlePrint(const char *text)
if (!useDisplay || !showingNormalScreen) if (!useDisplay || !showingNormalScreen)
return; return;
dispdev.print(text); dispdev->print(text);
} }
void Screen::handleOnPress() void Screen::handleOnPress()
{ {
// If screen was off, just wake it, otherwise advance to next frame // If screen was off, just wake it, otherwise advance to next frame
// If we are in a transition, the press must have bounced, drop it. // If we are in a transition, the press must have bounced, drop it.
if (ui.getUiState()->frameState == FIXED) { if (ui->getUiState()->frameState == FIXED) {
ui.nextFrame(); ui->nextFrame();
lastScreenTransition = millis(); lastScreenTransition = millis();
setFastFramerate(); setFastFramerate();
} }
@@ -1440,8 +1473,8 @@ void Screen::handleShowPrevFrame()
{ {
// If screen was off, just wake it, otherwise go back to previous frame // If screen was off, just wake it, otherwise go back to previous frame
// If we are in a transition, the press must have bounced, drop it. // If we are in a transition, the press must have bounced, drop it.
if (ui.getUiState()->frameState == FIXED) { if (ui->getUiState()->frameState == FIXED) {
ui.previousFrame(); ui->previousFrame();
lastScreenTransition = millis(); lastScreenTransition = millis();
setFastFramerate(); setFastFramerate();
} }
@@ -1451,8 +1484,8 @@ void Screen::handleShowNextFrame()
{ {
// If screen was off, just wake it, otherwise advance to next frame // If screen was off, just wake it, otherwise advance to next frame
// If we are in a transition, the press must have bounced, drop it. // If we are in a transition, the press must have bounced, drop it.
if (ui.getUiState()->frameState == FIXED) { if (ui->getUiState()->frameState == FIXED) {
ui.nextFrame(); ui->nextFrame();
lastScreenTransition = millis(); lastScreenTransition = millis();
setFastFramerate(); setFastFramerate();
} }
@@ -1467,7 +1500,7 @@ void Screen::setFastFramerate()
// We are about to start a transition so speed up fps // We are about to start a transition so speed up fps
targetFramerate = SCREEN_TRANSITION_FRAMERATE; targetFramerate = SCREEN_TRANSITION_FRAMERATE;
ui.setTargetFPS(targetFramerate); ui->setTargetFPS(targetFramerate);
setInterval(0); // redraw ASAP setInterval(0); // redraw ASAP
runASAP = true; runASAP = true;
} }
@@ -1554,7 +1587,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
} }
#endif #endif
} else { } else {
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \ // TODO: Raspberry Pi supports more than just the one screen size
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || ARCH_RASPBERRY_PI) && \
!defined(DISPLAY_FORCE_SMALL_FONTS) !defined(DISPLAY_FORCE_SMALL_FONTS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
imgInfoL1); imgInfoL1);
@@ -1581,7 +1615,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Jm // Jm
void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
#if HAS_WIFI #if HAS_WIFI && !defined(ARCH_RASPBERRY_PI)
const char *wifiName = config.network.wifi_ssid; const char *wifiName = config.network.wifi_ssid;
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
@@ -1635,69 +1669,19 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
} else if (WiFi.status() == WL_IDLE_STATUS) { } else if (WiFi.status() == WL_IDLE_STATUS) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting");
} else { }
#ifdef ARCH_ESP32
else {
// Codes: // Codes:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code // 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,
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Authentication Invalid"); WiFi.disconnectReasonName(static_cast<wifi_err_reason_t>(getWifiDisconnectReason())));
} 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");
}
} }
#else
else {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Unkown status: " + String(WiFi.status()));
}
#endif
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName)); display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
@@ -1743,37 +1727,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
display->drawString(x + 1, y, String("USB")); display->drawString(x + 1, y, String("USB"));
} }
auto mode = ""; auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
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;
}
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
if (config.display.heading_bold) if (config.display.heading_bold)
@@ -1840,23 +1794,6 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
heartbeat = !heartbeat; heartbeat = !heartbeat;
#endif #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) int Screen::handleStatusUpdate(const meshtastic::Status *arg)
{ {
@@ -1891,7 +1828,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
setFastFramerate(); setFastFramerate();
// TODO: We might also want switch to corresponding frame, // TODO: We might also want switch to corresponding frame,
// but we don't know the exact frame number. // but we don't know the exact frame number.
// ui.switchToFrame(0); // ui->switchToFrame(0);
} }
} }

View File

@@ -19,7 +19,6 @@ class Screen
void setup() {} void setup() {}
void setOn(bool) {} void setOn(bool) {}
void print(const char *) {} void print(const char *) {}
void adjustBrightness() {}
void doDeepSleep() {} void doDeepSleep() {}
void forceDisplay() {} void forceDisplay() {}
void startBluetoothPinScreen(uint32_t pin) {} void startBluetoothPinScreen(uint32_t pin) {}
@@ -161,7 +160,6 @@ class Screen : public concurrency::OSThread
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); } void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
// Implementation to Adjust Brightness // Implementation to Adjust Brightness
void adjustBrightness();
uint8_t brightness = BRIGHTNESS_DEFAULT; uint8_t brightness = BRIGHTNESS_DEFAULT;
/// Starts showing the Bluetooth PIN screen. /// Starts showing the Bluetooth PIN screen.
@@ -326,6 +324,8 @@ class Screen : public concurrency::OSThread
// Called periodically from the main loop. // Called periodically from the main loop.
int32_t runOnce() final; int32_t runOnce() final;
bool isAUTOOled = false;
private: private:
struct ScreenCmd { struct ScreenCmd {
Cmd cmd; Cmd cmd;
@@ -363,6 +363,9 @@ class Screen : public concurrency::OSThread
/// Try to start drawing ASAP /// Try to start drawing ASAP
void setFastFramerate(); 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. /// 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); static void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
@@ -384,22 +387,10 @@ class Screen : public concurrency::OSThread
DebugInfo debugInfo; DebugInfo debugInfo;
/// Display device /// Display device
OLEDDisplay *dispdev;
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
SH1106Wire dispdev;
#elif defined(USE_SSD1306)
SSD1306Wire dispdev;
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
TFTDisplay dispdev;
#elif defined(USE_EINK)
EInkDisplay dispdev;
#elif defined(USE_ST7567)
ST7567Wire dispdev;
#else
AutoOLEDWire dispdev;
#endif
/// UI helper for rendering to frames and switching between them /// UI helper for rendering to frames and switching between them
OLEDDisplayUi ui; OLEDDisplayUi *ui;
}; };
} // namespace graphics } // namespace graphics

View File

@@ -1,4 +1,8 @@
#include "configuration.h" #include "configuration.h"
#include "main.h"
#if ARCH_RASPBERRY_PI
#include "platform/portduino/PortduinoGlue.h"
#endif
#ifndef TFT_BACKLIGHT_ON #ifndef TFT_BACKLIGHT_ON
#define TFT_BACKLIGHT_ON HIGH #define TFT_BACKLIGHT_ON HIGH
@@ -81,8 +85,16 @@ class LGFX : public lgfx::LGFX_Device
{ {
auto cfg = _light_instance.config(); // Gets a structure for backlight settings. 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.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.freq = 44100; // PWM frequency of backlight
// cfg.pwm_channel = 1; // PWM channel number to use // cfg.pwm_channel = 1; // PWM channel number to use
@@ -94,7 +106,11 @@ class LGFX : public lgfx::LGFX_Device
} }
}; };
static LGFX tft; static LGFX *tft = nullptr;
#elif defined(RAK14014)
#include <TFT_eSPI.h>
TFT_eSPI *tft = nullptr;
#elif defined(ST7789_CS) #elif defined(ST7789_CS)
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip #include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
@@ -220,7 +236,7 @@ class LGFX : public lgfx::LGFX_Device
} }
}; };
static LGFX tft; static LGFX *tft = nullptr;
#elif defined(ILI9341_DRIVER) #elif defined(ILI9341_DRIVER)
@@ -309,23 +325,96 @@ class LGFX : public lgfx::LGFX_Device
} }
}; };
static LGFX tft; static LGFX *tft = nullptr;
#elif defined(ST7735_CS) #elif defined(ST7735_CS)
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip #include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h
#elif ARCH_RASPBERRY_PI
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_LCD *_panel_instance;
lgfx::Bus_SPI _bus_instance;
lgfx::ITouch *_touch_instance;
public:
LGFX(void)
{
_panel_instance = new lgfx::Panel_ST7789;
auto buscfg = _bus_instance.config();
buscfg.spi_mode = 0;
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
_bus_instance.config(buscfg); // applies the set value to the bus.
_panel_instance->setBus(&_bus_instance); // set the bus on the panel.
auto cfg = _panel_instance->config(); // Gets a structure for display panel settings.
LOG_DEBUG("Height: %d, Width: %d \n", settingsMap[displayHeight], settingsMap[displayWidth]);
cfg.pin_cs = settingsMap[displayCS]; // Pin number where CS is connected (-1 = disable)
cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
cfg.offset_x = 0; // Panel offset amount in X direction
cfg.offset_y = 0; // Panel offset amount in Y direction
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
cfg.readable = true; // Set to true if data can be read
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
cfg.dlen_16bit = false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
_panel_instance->config(cfg);
// Configure settings for touch control.
if (settingsMap[touchscreenModule]) {
if (settingsMap[touchscreenModule] == xpt2046) {
_touch_instance = new lgfx::Touch_XPT2046;
}
auto touch_cfg = _touch_instance->config();
touch_cfg.pin_cs = settingsMap[touchscreenCS];
touch_cfg.x_min = 0;
touch_cfg.x_max = settingsMap[displayHeight] - 1;
touch_cfg.y_min = 0;
touch_cfg.y_max = settingsMap[displayWidth] - 1;
touch_cfg.pin_int = settingsMap[touchscreenIRQ];
touch_cfg.bus_shared = true;
touch_cfg.offset_rotation = 1;
_touch_instance->config(touch_cfg);
_panel_instance->setTouch(_touch_instance);
}
setPanel(_panel_instance); // Sets the panel to use.
}
};
static LGFX *tft = nullptr;
#endif #endif
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) #if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014) || ARCH_RASPBERRY_PI
#include "SPILock.h" #include "SPILock.h"
#include "TFTDisplay.h" #include "TFTDisplay.h"
#include <SPI.h> #include <SPI.h>
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus) TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{ {
#ifdef SCREEN_ROTATE LOG_DEBUG("TFTDisplay!\n");
#if ARCH_RASPBERRY_PI
if (settingsMap[displayRotate]) {
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayHeight], settingsMap[configNames::displayWidth]);
} else {
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayWidth], settingsMap[configNames::displayHeight]);
}
#elif defined(SCREEN_ROTATE)
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH); setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);
#else #else
setGeometry(GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); setGeometry(GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
@@ -333,19 +422,26 @@ TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY g
} }
// Write the buffer to the display memory // Write the buffer to the display memory
void TFTDisplay::display(void) void TFTDisplay::display(bool fromBlank)
{ {
if (fromBlank)
tft->fillScreen(TFT_BLACK);
// tft->clear();
concurrency::LockGuard g(spiLock); concurrency::LockGuard g(spiLock);
uint16_t x, y; uint16_t x, y;
for (y = 0; y < displayHeight; y++) { for (y = 0; y < displayHeight; y++) {
for (x = 0; x < displayWidth; x++) { for (x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7)); auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7)); if (!fromBlank) {
if (isset != dblbuf_isset) { // get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
tft.drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK); auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
if (isset != dblbuf_isset) {
tft->drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
}
} else if (isset) {
tft->drawPixel(x, y, TFT_MESH);
} }
} }
} }
@@ -364,26 +460,65 @@ void TFTDisplay::sendCommand(uint8_t com)
// handle display on/off directly // handle display on/off directly
switch (com) { switch (com) {
case DISPLAYON: { case DISPLAYON: {
#if ARCH_RASPBERRY_PI
display(true);
if (settingsMap[displayBacklight] > 0)
digitalWrite(settingsMap[displayBacklight], TFT_BACKLIGHT_ON);
#elif 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) #if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
#endif #endif
#ifdef VTFT_CTRL_V03
if (heltec_version == 3) {
digitalWrite(VTFT_CTRL_V03, LOW);
} else {
digitalWrite(VTFT_CTRL_V05, LOW);
}
#endif
#ifdef VTFT_CTRL #ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, LOW); digitalWrite(VTFT_CTRL, LOW);
#endif #endif
#ifndef M5STACK
tft.setBrightness(128); #ifdef RAK14014
#elif !defined(M5STACK)
tft->setBrightness(128);
#endif #endif
break; break;
} }
case DISPLAYOFF: { case DISPLAYOFF: {
#if ARCH_RASPBERRY_PI
tft->clear();
if (settingsMap[displayBacklight] > 0)
digitalWrite(settingsMap[displayBacklight], !TFT_BACKLIGHT_ON);
#elif 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) #if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON); digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON);
#endif #endif
#ifdef VTFT_CTRL_V03
if (heltec_version == 3) {
digitalWrite(VTFT_CTRL_V03, HIGH);
} else {
digitalWrite(VTFT_CTRL_V05, HIGH);
}
#endif
#ifdef VTFT_CTRL #ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, HIGH); digitalWrite(VTFT_CTRL, HIGH);
#endif #endif
#ifndef M5STACK #ifdef RAK14014
tft.setBrightness(0); #elif !defined(M5STACK)
tft->setBrightness(0);
#endif #endif
break; break;
} }
@@ -398,14 +533,15 @@ void TFTDisplay::flipScreenVertically()
{ {
#if defined(T_WATCH_S3) #if defined(T_WATCH_S3)
LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation
tft.setRotation(0); tft->setRotation(0);
#endif #endif
} }
bool TFTDisplay::hasTouch(void) bool TFTDisplay::hasTouch(void)
{ {
#ifndef M5STACK #ifdef RAK14014
return tft.touch() != nullptr; #elif !defined(M5STACK)
return tft->touch() != nullptr;
#else #else
return false; return false;
#endif #endif
@@ -413,8 +549,9 @@ bool TFTDisplay::hasTouch(void)
bool TFTDisplay::getTouch(int16_t *x, int16_t *y) bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
{ {
#ifndef M5STACK #ifdef RAK14014
return tft.getTouch(x, y); #elif !defined(M5STACK)
return tft->getTouch(x, y);
#else #else
return false; return false;
#endif #endif
@@ -430,23 +567,47 @@ bool TFTDisplay::connect()
{ {
concurrency::LockGuard g(spiLock); concurrency::LockGuard g(spiLock);
LOG_INFO("Doing TFT init\n"); LOG_INFO("Doing TFT init\n");
#ifdef RAK14014
tft = new TFT_eSPI;
#else
tft = new LGFX;
#endif
#ifdef TFT_BL #ifdef TFT_BL
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
pinMode(TFT_BL, OUTPUT); pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
// pinMode(PIN_3V3_EN, OUTPUT);
// digitalWrite(PIN_3V3_EN, HIGH);
LOG_INFO("Power to TFT Backlight\n");
#endif #endif
tft.init(); #ifdef ST7735_BACKLIGHT_EN_V03
#if defined(M5STACK) if (heltec_version == 3) {
tft.setRotation(0); pinMode(ST7735_BACKLIGHT_EN_V03, OUTPUT);
#elif defined(T_DECK) || defined(PICOMPUTER_S3) digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
tft.setRotation(1); // T-Deck has the TFT in landscape } else {
#elif defined(T_WATCH_S3) pinMode(ST7735_BACKLIGHT_EN_V05, OUTPUT);
tft.setRotation(2); // T-Watch S3 left-handed orientation digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON);
#else }
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
#endif #endif
tft.fillScreen(TFT_BLACK);
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)
tft->setRotation(2); // T-Watch S3 left-handed orientation
#else
tft->setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
#endif
tft->fillScreen(TFT_BLACK);
return true; return true;
} }

View File

@@ -20,7 +20,8 @@ class TFTDisplay : public OLEDDisplay
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C); TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
// Write the buffer to the display memory // Write the buffer to the display memory
virtual void display(void) override; virtual void display() override { display(false); };
virtual void display(bool fromBlank);
// Turn the display upside down // Turn the display upside down
virtual void flipScreenVertically(); virtual void flipScreenVertically();

View File

@@ -14,7 +14,7 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF}; const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF}; const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \ #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || ARCH_RASPBERRY_PI) && \
!defined(DISPLAY_FORCE_SMALL_FONTS) !defined(DISPLAY_FORCE_SMALL_FONTS)
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff}; const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f}; const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
@@ -30,4 +30,4 @@ const uint8_t imgQuestion[] PROGMEM = {0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1,
const uint8_t imgSF[] PROGMEM = {0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5}; const uint8_t imgSF[] PROGMEM = {0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5};
#endif #endif
#include "img/icon.xbm" #include "img/icon.xbm"

184
src/input/LinuxInput.cpp Normal file
View File

@@ -0,0 +1,184 @@
#if ARCH_RASPBERRY_PI
#include "LinuxInput.h"
#include "configuration.h"
#include "platform/portduino/PortduinoGlue.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdint.h>
#include <stdio.h>
#include <string>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
// Inspired by https://github.com/librerpi/rpi-tools/blob/master/keyboard-proxy/main.c which is GPL-v2
LinuxInput::LinuxInput(const char *name) : concurrency::OSThread(name)
{
this->_originName = name;
}
void LinuxInput::deInit()
{
close(fd);
}
int32_t LinuxInput::runOnce()
{
if (firstTime) {
if (settingsStrings[keyboardDevice] == "")
return disable();
fd = open(settingsStrings[keyboardDevice].c_str(), O_RDWR);
if (fd < 0)
return disable();
ret = ioctl(fd, EVIOCGRAB, (void *)1);
if (ret != 0)
return disable();
epollfd = epoll_create1(0);
assert(epollfd >= 0);
ev.events = EPOLLIN;
ev.data.fd = fd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
perror("unable to epoll add");
return disable();
}
// This is the first time the OSThread library has called this function, so do port setup
firstTime = 0;
}
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, 1);
if (nfds < 0) {
printf("%d ", nfds);
perror("epoll_wait failed");
return disable();
} else if (nfds == 0) {
return 50;
}
int keys = 0;
memset(report, 0, 8);
for (int i = 0; i < nfds; i++) {
struct input_event ev[64];
int rd = read(events[i].data.fd, ev, sizeof(ev));
assert(rd > ((signed int)sizeof(struct input_event)));
for (int j = 0; j < rd / ((signed int)sizeof(struct input_event)); j++) {
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.source = this->_originName;
e.kbchar = 0;
unsigned int type, code;
type = ev[j].type;
code = ev[j].code;
int value = ev[j].value;
// printf("Event: time %ld.%06ld, ", ev[j].time.tv_sec, ev[j].time.tv_usec);
if (type == EV_KEY) {
uint8_t mod = 0;
switch (code) {
case KEY_LEFTCTRL:
mod = 0x01;
break;
case KEY_RIGHTCTRL:
mod = 0x10;
break;
case KEY_LEFTSHIFT:
mod = 0x02;
break;
case KEY_RIGHTSHIFT:
mod = 0x20;
break;
case KEY_LEFTALT:
mod = 0x04;
break;
case KEY_RIGHTALT:
mod = 0x40;
break;
case KEY_LEFTMETA:
mod = 0x08;
break;
}
if (value == 1) {
switch (code) {
case KEY_LEFTCTRL:
mod = 0x01;
break;
case KEY_RIGHTCTRL:
mod = 0x10;
break;
case KEY_LEFTSHIFT:
mod = 0x02;
break;
case KEY_RIGHTSHIFT:
mod = 0x20;
break;
case KEY_LEFTALT:
mod = 0x04;
break;
case KEY_RIGHTALT:
mod = 0x40;
break;
case KEY_LEFTMETA:
mod = 0x08;
break;
case KEY_ESC: // ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
break;
case KEY_BACK: // Back
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
// e.kbchar = key;
break;
case KEY_UP: // Up
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
break;
case KEY_DOWN: // Down
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
break;
case KEY_LEFT: // Left
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
break;
e.kbchar = 0xb4;
case KEY_RIGHT: // Right
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
break;
e.kbchar = 0xb7;
case KEY_ENTER: // Enter
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
break;
default: // all other keys
if (keymap[code]) {
e.inputEvent = ANYKEY;
e.kbchar = keymap[code];
}
break;
}
}
if (ev[j].value) {
modifiers |= mod;
} else {
modifiers &= ~mod;
}
report[0] = modifiers;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent == ANYKEY && (modifiers && 0x22))
e.kbchar = uppers[e.kbchar]; // doesn't get punctuation. Meh.
this->notifyObservers(&e);
}
}
}
return 50; // Keyscan every 50msec to avoid key bounce
}
#endif

65
src/input/LinuxInput.h Normal file
View File

@@ -0,0 +1,65 @@
#pragma once
#if ARCH_RASPBERRY_PI
#include "InputBroker.h"
#include "concurrency/OSThread.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <map>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX_EVENTS 10
class LinuxInput : public Observable<const InputEvent *>, public concurrency::OSThread
{
public:
explicit LinuxInput(const char *name);
void deInit(); // Strictly for cleanly "rebooting" the binary on native
protected:
virtual int32_t runOnce() override;
private:
const char *_originName;
bool firstTime = 1;
int shift = 0;
char key = 0;
char prevkey = 0;
InputEvent eventqueue[50]; // The Linux API will return multiple keypresses at a time. Queue them to not miss any.
int queue_length = 0;
int queue_progress = 0;
struct epoll_event events[MAX_EVENTS];
int fd;
int ret;
uint8_t report[8];
int epollfd;
struct epoll_event ev;
uint8_t modifiers = 0;
std::map<int, char> keymap{
{KEY_A, 'a'}, {KEY_B, 'b'}, {KEY_C, 'c'}, {KEY_D, 'd'}, {KEY_E, 'e'},
{KEY_F, 'f'}, {KEY_G, 'g'}, {KEY_H, 'h'}, {KEY_I, 'i'}, {KEY_J, 'j'},
{KEY_K, 'k'}, {KEY_L, 'l'}, {KEY_M, 'm'}, {KEY_N, 'n'}, {KEY_O, 'o'},
{KEY_P, 'p'}, {KEY_Q, 'q'}, {KEY_R, 'r'}, {KEY_S, 's'}, {KEY_T, 't'},
{KEY_U, 'u'}, {KEY_V, 'v'}, {KEY_W, 'w'}, {KEY_X, 'x'}, {KEY_Y, 'y'},
{KEY_Z, 'z'}, {KEY_BACKSPACE, 0x08}, {KEY_SPACE, ' '}, {KEY_1, '1'}, {KEY_2, '2'},
{KEY_3, '3'}, {KEY_4, '4'}, {KEY_5, '5'}, {KEY_6, '6'}, {KEY_7, '7'},
{KEY_8, '8'}, {KEY_9, '9'}, {KEY_0, '0'}, {KEY_DOT, '.'}, {KEY_COMMA, ','},
{KEY_MINUS, '-'}, {KEY_EQUAL, '='}, {KEY_LEFTBRACE, '['}, {KEY_RIGHTBRACE, ']'}, {KEY_BACKSLASH, '\\'},
{KEY_SEMICOLON, ';'}, {KEY_APOSTROPHE, '\''}, {KEY_SLASH, '/'}, {KEY_TAB, 0x09}};
std::map<char, char> uppers{{'a', 'A'}, {'b', 'B'}, {'c', 'C'}, {'d', 'D'}, {'e', 'E'}, {'f', 'F'}, {'g', 'G'}, {'h', 'H'},
{'i', 'I'}, {'j', 'J'}, {'k', 'K'}, {'l', 'L'}, {'m', 'M'}, {'n', 'N'}, {'o', 'O'}, {'p', 'P'},
{'q', 'Q'}, {'r', 'R'}, {'s', 'S'}, {'t', 'T'}, {'u', 'U'}, {'v', 'V'}, {'w', 'W'}, {'x', 'X'},
{'y', 'Y'}, {'z', 'Z'}, {'1', '!'}, {'2', '@'}, {'3', '#'}, {'4', '$'}, {'5', '%'}, {'6', '^'},
{'7', '&'}, {'8', '*'}, {'9', '('}, {'0', ')'}, {'.', '>'}, {',', '<'}, {'-', '_'}, {'=', '+'},
{'[', '{'}, {']', '}'}, {'\\', '|'}, {';', ':'}, {'\'', '"'}, {'/', '?'}};
};
#endif

View File

@@ -0,0 +1,14 @@
#if ARCH_RASPBERRY_PI
#include "LinuxInputImpl.h"
#include "InputBroker.h"
LinuxInputImpl *aLinuxInputImpl;
LinuxInputImpl::LinuxInputImpl() : LinuxInput("LinuxInput") {}
void LinuxInputImpl::init()
{
inputBroker->registerSource(this);
}
#endif

View File

@@ -0,0 +1,21 @@
#ifdef ARCH_RASPBERRY_PI
#pragma once
#include "LinuxInput.h"
#include "main.h"
/**
* @brief The idea behind this class to have static methods for the event handlers.
* Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
* Technically you can have as many rotary encoders hardver attached
* to your device as you wish, but you always need to have separate event
* handlers, thus you need to have a RotaryEncoderInterrupt implementation.
*/
class LinuxInputImpl : public LinuxInput
{
public:
LinuxInputImpl();
void init();
};
extern LinuxInputImpl *aLinuxInputImpl;
#endif

View File

@@ -2,6 +2,11 @@
#include "InputBroker.h" #include "InputBroker.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "configuration.h" #include "configuration.h"
#include "modules/ExternalNotificationModule.h"
#ifdef ARCH_RASPBERRY_PI
#include "platform/portduino/PortduinoGlue.h"
#endif
TouchScreenImpl1 *touchScreenImpl1; TouchScreenImpl1 *touchScreenImpl1;
@@ -12,7 +17,14 @@ TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTo
void TouchScreenImpl1::init() void TouchScreenImpl1::init()
{ {
#if !HAS_TOUCHSCREEN #if ARCH_RASPBERRY_PI
if (settingsMap[touchscreenModule]) {
TouchScreenBase::init(true);
inputBroker->registerSource(this);
} else {
TouchScreenBase::init(false);
}
#elif !HAS_TOUCHSCREEN
TouchScreenBase::init(false); TouchScreenBase::init(false);
return; return;
#else #else
@@ -63,7 +75,11 @@ void TouchScreenImpl1::onEvent(const TouchEvent &event)
break; break;
} }
case TOUCH_ACTION_TAP: { case TOUCH_ACTION_TAP: {
powerFSM.trigger(EVENT_INPUT); if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
externalNotificationModule->stopNow();
} else {
powerFSM.trigger(EVENT_INPUT);
}
break; break;
} }
default: default:

View File

@@ -29,11 +29,9 @@
#include "target_specific.h" #include "target_specific.h"
#include <Wire.h> #include <Wire.h>
#include <memory> #include <memory>
#include <utility>
// #include <driver/rtc_io.h> // #include <driver/rtc_io.h>
#include "mesh/eth/ethClient.h"
#include "mesh/http/WiFiAPClient.h"
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
#include "nimble/NimbleBluetooth.h" #include "nimble/NimbleBluetooth.h"
@@ -47,10 +45,12 @@ NRF52Bluetooth *nrf52Bluetooth;
#if HAS_WIFI #if HAS_WIFI
#include "mesh/api/WiFiServerAPI.h" #include "mesh/api/WiFiServerAPI.h"
#include "mesh/wifi/WiFiAPClient.h"
#endif #endif
#if HAS_ETHERNET #if HAS_ETHERNET
#include "mesh/api/ethServerAPI.h" #include "mesh/api/ethServerAPI.h"
#include "mesh/eth/ethClient.h"
#endif #endif
#include "mqtt/MQTT.h" #include "mqtt/MQTT.h"
@@ -66,7 +66,15 @@ NRF52Bluetooth *nrf52Bluetooth;
#include "platform/portduino/SimRadio.h" #include "platform/portduino/SimRadio.h"
#endif #endif
#if HAS_BUTTON #ifdef ARCH_RASPBERRY_PI
#include "linux/LinuxHardwareI2C.h"
#include "platform/portduino/PortduinoGlue.h"
#include <fstream>
#include <iostream>
#include <string>
#endif
#if HAS_BUTTON || defined(ARCH_RASPBERRY_PI)
#include "ButtonThread.h" #include "ButtonThread.h"
#endif #endif
#include "PowerFSMThread.h" #include "PowerFSMThread.h"
@@ -76,6 +84,11 @@ NRF52Bluetooth *nrf52Bluetooth;
#include "AmbientLightingThread.h" #include "AmbientLightingThread.h"
#endif #endif
#ifdef HAS_I2S
#include "AudioThread.h"
AudioThread *audioThread;
#endif
using namespace concurrency; using namespace concurrency;
// We always create a screen object, but we only init it if we find the hardware // We always create a screen object, but we only init it if we find the hardware
@@ -114,6 +127,7 @@ ATECCX08A atecc;
#ifdef T_WATCH_S3 #ifdef T_WATCH_S3
Adafruit_DRV2605 drv; Adafruit_DRV2605 drv;
#endif #endif
bool isVibrating = false; bool isVibrating = false;
bool eink_found = true; bool eink_found = true;
@@ -122,18 +136,37 @@ uint32_t serialSinceMsec;
bool pmu_found; bool pmu_found;
// Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan // Array map of sensor types with i2c address and wire as we'll find in the i2c scan
uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = { std::pair<uint8_t, TwoWire *> nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {};
0}; // one is enough, missing elements will be initialized to 0 anyway.
Router *router = NULL; // Users of router don't care what sort of subclass implements that API 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() const char *getDeviceName()
{ {
uint8_t dmac[6]; uint8_t dmac[6];
#ifdef ARCH_RASPBERRY_PI
getPiMacAddr(dmac);
#else
getMacAddr(dmac); getMacAddr(dmac);
#endif
// Meshtastic_ab3c or Shortname_abcd // Meshtastic_ab3c or Shortname_abcd
static char name[20]; static char name[20];
snprintf(name, sizeof(name), "%02x%02x", dmac[4], dmac[5]); snprintf(name, sizeof(name), "%02x%02x", dmac[4], dmac[5]);
@@ -146,6 +179,25 @@ const char *getDeviceName()
return name; 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 int32_t ledBlinker()
{ {
static bool ledOn; static bool ledOn;
@@ -159,13 +211,13 @@ static int32_t ledBlinker()
uint32_t timeLastPowered = 0; uint32_t timeLastPowered = 0;
#if HAS_BUTTON #if HAS_BUTTON || defined(ARCH_RASPBERRY_PI)
bool ButtonThread::shutdown_on_long_stop = false; bool ButtonThread::shutdown_on_long_stop = false;
#endif #endif
static Periodic *ledPeriodic; static Periodic *ledPeriodic;
static OSThread *powerFSMthread; static OSThread *powerFSMthread;
#if HAS_BUTTON #if HAS_BUTTON || defined(ARCH_RASPBERRY_PI)
static OSThread *buttonThread; static OSThread *buttonThread;
uint32_t ButtonThread::longPressTime = 0; uint32_t ButtonThread::longPressTime = 0;
#endif #endif
@@ -216,11 +268,63 @@ void setup()
digitalWrite(PIN_EINK_PWR_ON, HIGH); digitalWrite(PIN_EINK_PWR_ON, HIGH);
#endif #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); pinMode(VEXT_ENABLE, OUTPUT);
digitalWrite(VEXT_ENABLE, 0); // turn on the display power digitalWrite(VEXT_ENABLE, 0); // turn on the display power
#endif #endif
#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
#if defined(VTFT_CTRL) #if defined(VTFT_CTRL)
pinMode(VTFT_CTRL, OUTPUT); pinMode(VTFT_CTRL, OUTPUT);
digitalWrite(VTFT_CTRL, LOW); digitalWrite(VTFT_CTRL, LOW);
@@ -265,11 +369,19 @@ void setup()
#endif #endif
#ifdef I2C_SDA1 #if defined(I2C_SDA1) && defined(ARCH_RP2040)
Wire1.setSDA(I2C_SDA1);
Wire1.setSCL(I2C_SCL1);
Wire1.begin();
#elif defined(I2C_SDA1) && !defined(ARCH_RP2040)
Wire1.begin(I2C_SDA1, I2C_SCL1); Wire1.begin(I2C_SDA1, I2C_SCL1);
#endif #endif
#ifdef I2C_SDA #if defined(I2C_SDA) && defined(ARCH_RP2040)
Wire.setSDA(I2C_SDA);
Wire.setSCL(I2C_SCL);
Wire.begin();
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
Wire.begin(I2C_SDA, I2C_SCL); Wire.begin(I2C_SDA, I2C_SCL);
#elif HAS_WIRE #elif HAS_WIRE
Wire.begin(); Wire.begin();
@@ -319,12 +431,22 @@ void setup()
LOG_INFO("Scanning for i2c devices...\n"); LOG_INFO("Scanning for i2c devices...\n");
#ifdef I2C_SDA1 #if defined(I2C_SDA1) && defined(ARCH_RP2040)
Wire1.setSDA(I2C_SDA1);
Wire1.setSCL(I2C_SCL1);
Wire1.begin();
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
#elif defined(I2C_SDA1) && !defined(ARCH_RP2040)
Wire1.begin(I2C_SDA1, I2C_SCL1); Wire1.begin(I2C_SDA1, I2C_SCL1);
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1); i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
#endif #endif
#ifdef I2C_SDA #if defined(I2C_SDA) && defined(ARCH_RP2040)
Wire.setSDA(I2C_SDA);
Wire.setSCL(I2C_SCL);
Wire.begin();
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
Wire.begin(I2C_SDA, I2C_SCL); Wire.begin(I2C_SDA, I2C_SCL);
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE); i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#elif HAS_WIRE #elif HAS_WIRE
@@ -334,6 +456,10 @@ void setup()
auto i2cCount = i2cScanner->countDevices(); auto i2cCount = i2cScanner->countDevices();
if (i2cCount == 0) { if (i2cCount == 0) {
LOG_INFO("No I2C devices found\n"); LOG_INFO("No I2C devices found\n");
Wire.end();
#ifdef I2C_SDA1
Wire1.end();
#endif
} else { } else {
LOG_INFO("%i I2C devices found\n", i2cCount); LOG_INFO("%i I2C devices found\n", i2cCount);
} }
@@ -420,7 +546,8 @@ void setup()
{ \ { \
auto found = i2cScanner->find(SCANNER_T); \ auto found = i2cScanner->find(SCANNER_T); \
if (found.type != ScanI2C::DeviceType::NONE) { \ 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)); \ LOG_DEBUG("found i2c sensor %s\n", STRING(PB_T)); \
} \ } \
} }
@@ -430,6 +557,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280) 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::INA260, meshtastic_TelemetrySensorType_INA260)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219) 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::MCP9808, meshtastic_TelemetrySensorType_MCP9808) SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31) SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31)
@@ -476,13 +604,16 @@ void setup()
// but we need to do this after main cpu init (esp32setup), because we need the random seed set // but we need to do this after main cpu init (esp32setup), because we need the random seed set
nodeDB.init(); nodeDB.init();
// If we're taking on the repeater role, use flood router // If we're taking on the repeater role, use flood router and turn off 3V3_S rail because peripherals are not needed
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
router = new FloodingRouter(); router = new FloodingRouter();
else #ifdef PIN_3V3_EN
digitalWrite(PIN_3V3_EN, LOW);
#endif
} else
router = new ReliableRouter(); router = new ReliableRouter();
#if HAS_BUTTON #if HAS_BUTTON || defined(ARCH_RASPBERRY_PI)
// Buttons. Moved here cause we need NodeDB to be initialized // Buttons. Moved here cause we need NodeDB to be initialized
buttonThread = new ButtonThread(); buttonThread = new ButtonThread();
#endif #endif
@@ -527,24 +658,24 @@ void setup()
initSPI(); initSPI();
#ifdef ARCH_RP2040 #ifdef ARCH_RP2040
#ifdef HW_SPI1_DEVICE #ifdef HW_SPI1_DEVICE
SPI1.setSCK(RF95_SCK); SPI1.setSCK(LORA_SCK);
SPI1.setTX(RF95_MOSI); SPI1.setTX(LORA_MOSI);
SPI1.setRX(RF95_MISO); SPI1.setRX(LORA_MISO);
pinMode(RF95_NSS, OUTPUT); pinMode(LORA_CS, OUTPUT);
digitalWrite(RF95_NSS, HIGH); digitalWrite(LORA_CS, HIGH);
SPI1.begin(false); SPI1.begin(false);
#else // HW_SPI1_DEVICE #else // HW_SPI1_DEVICE
SPI.setSCK(RF95_SCK); SPI.setSCK(LORA_SCK);
SPI.setTX(RF95_MOSI); SPI.setTX(LORA_MOSI);
SPI.setRX(RF95_MISO); SPI.setRX(LORA_MISO);
SPI.begin(false); SPI.begin(false);
#endif // HW_SPI1_DEVICE #endif // HW_SPI1_DEVICE
#elif !defined(ARCH_ESP32) // ARCH_RP2040 #elif !defined(ARCH_ESP32) // ARCH_RP2040
SPI.begin(); SPI.begin();
#else #else
// ESP32 // ESP32
SPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS); SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
LOG_WARN("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)\n", RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS); LOG_WARN("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)\n", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
SPI.setFrequency(4000000); SPI.setFrequency(4000000);
#endif #endif
@@ -553,7 +684,10 @@ void setup()
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time) readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
gps = GPS::createGps(); // If we're taking on the repeater role, ignore GPS
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
gps = GPS::createGps();
}
if (gps) { if (gps) {
gpsStatus->observe(&gps->newStatus); gpsStatus->observe(&gps->newStatus);
} else { } else {
@@ -561,6 +695,11 @@ void setup()
} }
nodeStatus->observe(&nodeDB.newStatus); nodeStatus->observe(&nodeDB.newStatus);
#ifdef HAS_I2S
LOG_DEBUG("Starting audio thread\n");
audioThread = new AudioThread();
#endif
service.init(); service.init();
// Now that the mesh service is created, create any modules // Now that the mesh service is created, create any modules
@@ -576,6 +715,10 @@ void setup()
// the current region name) // the current region name)
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
screen->setup(); screen->setup();
#elif ARCH_RASPBERRY_PI
if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) {
screen->setup();
}
#else #else
if (screen_found.port != ScanI2C::I2CPort::NO_I2C) if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
screen->setup(); screen->setup();
@@ -589,7 +732,51 @@ void setup()
digitalWrite(SX126X_ANT_SW, 1); digitalWrite(SX126X_ANT_SW, 1);
#endif #endif
#ifdef HW_SPI1_DEVICE #ifdef ARCH_RASPBERRY_PI
if (settingsMap[use_sx1262]) {
if (!rIf) {
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
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) {
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
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");
}
}
} else if (settingsMap[use_sx1280]) {
if (!rIf) {
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
LOG_ERROR("Failed to find SX1280 radio\n");
delete rIf;
rIf = NULL;
exit(EXIT_FAILURE);
} else {
LOG_INFO("SX1280 Radio init succeeded, using SX1280 radio\n");
}
}
}
#elif defined(HW_SPI1_DEVICE)
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings); LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
#else // HW_SPI1_DEVICE #else // HW_SPI1_DEVICE
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
@@ -624,7 +811,7 @@ void setup()
#if defined(RF95_IRQ) #if defined(RF95_IRQ)
if (!rIf) { if (!rIf) {
rIf = new RF95Interface(RadioLibHAL, RF95_NSS, RF95_IRQ, RF95_RESET, RF95_DIO1); rIf = new RF95Interface(RadioLibHAL, LORA_CS, RF95_IRQ, RF95_RESET, RF95_DIO1);
if (!rIf->init()) { if (!rIf->init()) {
LOG_WARN("Failed to find RF95 radio\n"); LOG_WARN("Failed to find RF95 radio\n");
delete rIf; delete rIf;
@@ -635,7 +822,7 @@ void setup()
} }
#endif #endif
#if defined(USE_SX1262) #if defined(USE_SX1262) && !defined(ARCH_RASPBERRY_PI)
if (!rIf) { if (!rIf) {
rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY); rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) { if (!rIf->init()) {
@@ -704,11 +891,15 @@ void setup()
#ifndef ARCH_PORTDUINO #ifndef ARCH_PORTDUINO
// Initialize Wifi // Initialize Wifi
#if HAS_WIFI
initWifi(); initWifi();
#endif
#if HAS_ETHERNET
// Initialize Ethernet // Initialize Ethernet
initEthernet(); initEthernet();
#endif #endif
#endif
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
// Start web server thread. // Start web server thread.
@@ -736,7 +927,6 @@ void setup()
// This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values // This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values
PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS 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(); powerFSMthread = new PowerFSMThread();
setCPUFast(false); // 80MHz is fine for our slow peripherals setCPUFast(false); // 80MHz is fine for our slow peripherals
} }
@@ -807,4 +997,4 @@ void loop()
mainDelay.delay(delayMsec); mainDelay.delay(delayMsec);
} }
// if (didWake) LOG_DEBUG("wake!\n"); // if (didWake) LOG_DEBUG("wake!\n");
} }

View File

@@ -42,6 +42,12 @@ extern ATECCX08A atecc;
#include <Adafruit_DRV2605.h> #include <Adafruit_DRV2605.h>
extern Adafruit_DRV2605 drv; extern Adafruit_DRV2605 drv;
#endif #endif
#ifdef HAS_I2S
#include "AudioThread.h"
extern AudioThread *audioThread;
#endif
extern bool isVibrating; extern bool isVibrating;
extern int TCPPort; // set by Portduino extern int TCPPort; // set by Portduino
@@ -56,6 +62,7 @@ extern graphics::Screen *screen;
// Return a human readable string of the form "Meshtastic_ab13" // Return a human readable string of the form "Meshtastic_ab13"
const char *getDeviceName(); const char *getDeviceName();
void getPiMacAddr(uint8_t *dmac);
extern uint32_t timeLastPowered; extern uint32_t timeLastPowered;
@@ -64,11 +71,13 @@ extern uint32_t shutdownAtMsec;
extern uint32_t serialSinceMsec; 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 // 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. // This will suppress the current delay and instead try to run ASAP.
extern bool runASAP; extern bool runASAP;
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds(); void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds(), enterDfuMode();
meshtastic_DeviceMetadata getDeviceMetadata(); meshtastic_DeviceMetadata getDeviceMetadata();

View File

@@ -1,5 +1,6 @@
#include "Channels.h" #include "Channels.h"
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "DisplayFormatters.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "configuration.h" #include "configuration.h"
@@ -183,7 +184,7 @@ void Channels::onConfigChanged()
{ {
// Make sure the phone hasn't mucked anything up // Make sure the phone hasn't mucked anything up
for (int i = 0; i < channelFile.channels_count; i++) { for (int i = 0; i < channelFile.channels_count; i++) {
meshtastic_Channel &ch = fixupChannel(i); const meshtastic_Channel &ch = fixupChannel(i);
if (ch.role == meshtastic_Channel_Role_PRIMARY) if (ch.role == meshtastic_Channel_Role_PRIMARY)
primaryIndex = i; primaryIndex = i;
@@ -239,38 +240,9 @@ const char *Channels::getName(size_t chIndex)
const char *channelName = channelSettings.name; const char *channelName = channelSettings.name;
if (!*channelName) { // emptystring if (!*channelName) { // emptystring
// Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case // 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) { if (config.lora.use_preset) {
switch (config.lora.modem_preset) { channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
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;
}
} else { } else {
channelName = "Custom"; channelName = "Custom";
} }

View File

@@ -73,58 +73,3 @@ template <class T> class MemoryDynamic : public Allocator<T>
return p; return p;
} }
}; };
/**
* A pool based allocator
*
*/
template <class T> class MemoryPool : public Allocator<T>
{
PointerQueue<T> dead;
T *buf; // our large raw block of memory
size_t maxElements;
public:
explicit MemoryPool(size_t _maxElements) : dead(_maxElements), maxElements(_maxElements)
{
buf = new T[maxElements];
// prefill dead
for (size_t i = 0; i < maxElements; i++)
release(&buf[i]);
}
~MemoryPool() { delete[] buf; }
/// Return a buffer for use by others
void release(T *p)
{
assert(p >= buf &&
(size_t)(p - buf) <
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
assert(dead.enqueue(p, 0));
}
#ifdef HAS_FREE_RTOS
/// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-)
void releaseFromISR(T *p, BaseType_t *higherPriWoken)
{
assert(p >= buf &&
(size_t)(p - buf) <
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
assert(dead.enqueueFromISR(p, higherPriWoken));
}
#endif
protected:
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you
/// probably don't want this version).
virtual T *alloc(TickType_t maxWait)
{
T *p = dead.dequeuePtr(maxWait);
assert(p);
return p;
}
};

View File

@@ -140,6 +140,22 @@ void MeshService::reloadOwner(bool shouldSave)
} }
} }
// search the queue for a request id and return the matching nodenum
NodeNum MeshService::getNodenumFromRequestId(uint32_t request_id)
{
NodeNum nodenum = 0;
for (int i = 0; i < toPhoneQueue.numUsed(); i++) {
meshtastic_MeshPacket *p = toPhoneQueue.dequeuePtr(0);
if (p->id == request_id) {
nodenum = p->to;
// make sure to continue this to make one full loop
}
// put it right back on the queue
toPhoneQueue.enqueue(p, 0);
}
return nodenum;
}
/** /**
* Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh) * Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh)
* Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep a * Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep a
@@ -267,14 +283,22 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
void MeshService::sendToPhone(meshtastic_MeshPacket *p) void MeshService::sendToPhone(meshtastic_MeshPacket *p)
{ {
perhapsDecode(p);
if (toPhoneQueue.numFree() == 0) { if (toPhoneQueue.numFree() == 0) {
LOG_WARN("ToPhone queue is full, discarding oldest\n"); if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0); p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) {
if (d) LOG_WARN("ToPhone queue is full, discarding oldest\n");
releaseToPool(d); 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)); assert(toPhoneQueue.enqueue(p, 0));
fromNum++; fromNum++;
} }
@@ -312,7 +336,9 @@ meshtastic_NodeInfoLite *MeshService::refreshLocalMeshNode()
position.time = getValidTime(RTCQualityFromNet); position.time = getValidTime(RTCQualityFromNet);
updateBatteryLevel(powerStatus->getBatteryChargePercent()); if (powerStatus->getHasBattery() == 1) {
updateBatteryLevel(powerStatus->getBatteryChargePercent());
}
return node; return node;
} }
@@ -335,7 +361,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
// Used fixed position if configured regalrdless of GPS lock // Used fixed position if configured regalrdless of GPS lock
if (config.position.fixed_position) { if (config.position.fixed_position) {
LOG_WARN("Using fixed position\n"); LOG_WARN("Using fixed position\n");
pos = ConvertToPosition(node->position); pos = TypeConversions::ConvertToPosition(node->position);
} }
// Add a fresh timestamp // Add a fresh timestamp

View File

@@ -82,6 +82,9 @@ class MeshService
/// Return the next MqttClientProxyMessage packet destined to the phone. /// Return the next MqttClientProxyMessage packet destined to the phone.
meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); } meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); }
// search the queue for a request id and return the matching nodenum
NodeNum getNodenumFromRequestId(uint32_t request_id);
// Release QueueStatus packet to pool // Release QueueStatus packet to pool
void releaseQueueStatusToPool(meshtastic_QueueStatus *p) { queueStatusPool.release(p); } void releaseQueueStatusToPool(meshtastic_QueueStatus *p) { queueStatusPool.release(p); }
@@ -126,6 +129,8 @@ class MeshService
bool isToPhoneQueueEmpty(); bool isToPhoneQueueEmpty();
ErrorCode sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id);
private: private:
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh /// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
/// returns 0 to allow further processing /// returns 0 to allow further processing
@@ -135,8 +140,6 @@ class MeshService
/// needs to keep the packet around it makes a copy /// needs to keep the packet around it makes a copy
int handleFromRadio(const meshtastic_MeshPacket *p); int handleFromRadio(const meshtastic_MeshPacket *p);
friend class RoutingModule; friend class RoutingModule;
ErrorCode sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id);
}; };
extern MeshService service; extern MeshService service;

View File

@@ -21,12 +21,16 @@
#include <pb_encode.h> #include <pb_encode.h>
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "modules/esp32/StoreForwardModule.h" #include "modules/esp32/StoreForwardModule.h"
#include <Preferences.h> #include <Preferences.h>
#include <nvs_flash.h> #include <nvs_flash.h>
#endif #endif
#ifdef ARCH_RASPBERRY_PI
#include "platform/portduino/PortduinoGlue.h"
#endif
#ifdef ARCH_NRF52 #ifdef ARCH_NRF52
#include <bluefruit.h> #include <bluefruit.h>
#include <utility/bonding.h> #include <utility/bonding.h>
@@ -191,6 +195,12 @@ void NodeDB::installDefaultConfig()
config.bluetooth.fixed_pin = defaultBLEPin; config.bluetooth.fixed_pin = defaultBLEPin;
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
bool hasScreen = true; bool hasScreen = true;
#elif ARCH_RASPBERRY_PI
bool hasScreen = false;
if (settingsMap[displayPanel])
hasScreen = true;
else
hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
#else #else
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C; bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
#endif #endif
@@ -200,7 +210,7 @@ void NodeDB::installDefaultConfig()
config.position.position_flags = 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_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING |
meshtastic_Config_PositionConfig_PositionFlags_DOP); meshtastic_Config_PositionConfig_PositionFlags_DOP | meshtastic_Config_PositionConfig_PositionFlags_SATINVIEW);
#ifdef T_WATCH_S3 #ifdef T_WATCH_S3
config.display.screen_on_secs = 30; config.display.screen_on_secs = 30;
@@ -213,7 +223,6 @@ void NodeDB::installDefaultConfig()
void NodeDB::initConfigIntervals() void NodeDB::initConfigIntervals()
{ {
config.position.gps_update_interval = default_gps_update_interval; config.position.gps_update_interval = default_gps_update_interval;
config.position.gps_attempt_time = default_gps_attempt_time;
config.position.position_broadcast_secs = default_broadcast_interval_secs; config.position.position_broadcast_secs = default_broadcast_interval_secs;
config.power.ls_secs = default_ls_secs; config.power.ls_secs = default_ls_secs;
@@ -245,15 +254,26 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.external_notification.output_ms = 1000; moduleConfig.external_notification.output_ms = 1000;
moduleConfig.external_notification.nag_timeout = 60; moduleConfig.external_notification.nag_timeout = 60;
#endif #endif
#ifdef T_WATCH_S3 #ifdef HAS_I2S
// Don't worry about the other settings, we'll use the DRV2056 behavior for notifications // Don't worry about the other settings for T-Watch, we'll also use the DRV2056 behavior for notifications
moduleConfig.external_notification.enabled = true; moduleConfig.external_notification.enabled = true;
moduleConfig.external_notification.use_i2s_as_buzzer = true;
moduleConfig.external_notification.alert_message_buzzer = true;
moduleConfig.external_notification.nag_timeout = 60;
#endif
#ifdef NANO_G2_ULTRA
moduleConfig.external_notification.enabled = true;
moduleConfig.external_notification.alert_message = true;
moduleConfig.external_notification.output_ms = 100;
moduleConfig.external_notification.active = true;
#endif #endif
moduleConfig.has_canned_message = true; moduleConfig.has_canned_message = true;
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(moduleConfig.mqtt.address)); 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.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password)); 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.has_neighbor_info = true;
moduleConfig.neighbor_info.enabled = false; moduleConfig.neighbor_info.enabled = false;
@@ -280,11 +300,30 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
initModuleConfigIntervals(); initModuleConfigIntervals();
} else if (role == meshtastic_Config_DeviceConfig_Role_REPEATER) { } else if (role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
config.display.screen_on_secs = 1; config.display.screen_on_secs = 1;
} else if (role == meshtastic_Config_DeviceConfig_Role_TRACKER) {
config.position.gps_update_interval = 30;
} else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) { } else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) {
moduleConfig.telemetry.environment_measurement_enabled = true; moduleConfig.telemetry.environment_measurement_enabled = true;
moduleConfig.telemetry.environment_update_interval = 300; moduleConfig.telemetry.environment_update_interval = 300;
} else if (role == meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND) {
config.position.position_broadcast_smart_enabled = false;
config.position.position_broadcast_secs = 300; // Every 5 minutes
} 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;
} else if (role == meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY;
config.device.node_info_broadcast_secs = UINT32_MAX;
config.position.position_broadcast_smart_enabled = false;
config.position.position_broadcast_secs = UINT32_MAX;
moduleConfig.neighbor_info.update_interval = UINT32_MAX;
moduleConfig.telemetry.device_update_interval = UINT32_MAX;
moduleConfig.telemetry.environment_update_interval = UINT32_MAX;
moduleConfig.telemetry.air_quality_interval = UINT32_MAX;
} }
} }
@@ -305,13 +344,27 @@ void NodeDB::installDefaultChannels()
void NodeDB::resetNodes() void NodeDB::resetNodes()
{ {
devicestate.node_db_lite_count = 0; devicestate.node_db_lite_count = 1;
memset(devicestate.node_db_lite, 0, sizeof(devicestate.node_db_lite)); std::fill(&devicestate.node_db_lite[1], &devicestate.node_db_lite[MAX_NUM_NODES - 1], meshtastic_NodeInfoLite());
saveDeviceStateToDisk(); saveDeviceStateToDisk();
if (neighborInfoModule && moduleConfig.neighbor_info.enabled) if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
neighborInfoModule->resetNeighbors(); 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() void NodeDB::cleanupMeshDB()
{ {
int newPos = 0, removed = 0; int newPos = 0, removed = 0;
@@ -345,7 +398,6 @@ void NodeDB::installDefaultDeviceState()
pickNewNodeNum(); // based on macaddr now pickNewNodeNum(); // based on macaddr now
snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %02x%02x", ourMacAddr[4], ourMacAddr[5]); snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %02x%02x", ourMacAddr[4], ourMacAddr[5]);
snprintf(owner.short_name, sizeof(owner.short_name), "%02x%02x", ourMacAddr[4], ourMacAddr[5]); snprintf(owner.short_name, sizeof(owner.short_name), "%02x%02x", ourMacAddr[4], ourMacAddr[5]);
snprintf(owner.id, sizeof(owner.id), "!%08x", getNodeNum()); // Default node ID now based on nodenum snprintf(owner.id, sizeof(owner.id), "!%08x", getNodeNum()); // Default node ID now based on nodenum
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr)); memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
} }
@@ -370,6 +422,8 @@ void NodeDB::init()
// Set our board type so we can share it with others // Set our board type so we can share it with others
owner.hw_model = HW_VENDOR; owner.hw_model = HW_VENDOR;
// Ensure user (nodeinfo) role is set to whatever we're configured to
owner.role = config.device.role;
// Include our owner in the node db under our nodenum // Include our owner in the node db under our nodenum
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum()); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
@@ -410,7 +464,11 @@ void NodeDB::init()
*/ */
void NodeDB::pickNewNodeNum() void NodeDB::pickNewNodeNum()
{ {
#ifdef ARCH_RASPBERRY_PI
getPiMacAddr(ourMacAddr); // Make sure ourMacAddr is set
#else
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
#endif
// Pick an initial nodenum based on the macaddr // Pick an initial nodenum based on the macaddr
NodeNum nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5]; NodeNum nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
@@ -422,6 +480,7 @@ void NodeDB::pickNewNodeNum()
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, so trying for 0x%x\n", nodeNum, candidate); LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, so trying for 0x%x\n", nodeNum, candidate);
nodeNum = candidate; nodeNum = candidate;
} }
LOG_WARN("Using nodenum 0x%x \n", nodeNum);
myNodeInfo.my_node_num = nodeNum; myNodeInfo.my_node_num = nodeNum;
} }
@@ -687,8 +746,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, 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); p.longitude_i, p.altitude);
info->position = ConvertToPositionLite(p); setLocalPosition(p);
localPosition = p; info->position = TypeConversions::ConvertToPositionLite(p);
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) { } 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 // FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
// (stop-gap fix for issue #900) // (stop-gap fix for issue #900)
@@ -706,7 +765,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
uint32_t tmp_time = info->position.time; uint32_t tmp_time = info->position.time;
// Next, update atomically // Next, update atomically
info->position = ConvertToPositionLite(p); info->position = TypeConversions::ConvertToPositionLite(p);
// Last, restore any fields that may have been overwritten // Last, restore any fields that may have been overwritten
if (!info->position.time) 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?) /// Return the number of nodes we've heard from recently (within the last 2 hrs?)
size_t getNumOnlineMeshNodes(); size_t getNumOnlineMeshNodes();
void initConfigIntervals(), initModuleConfigIntervals(), resetNodes(); void initConfigIntervals(), initModuleConfigIntervals(), resetNodes(), removeNodeByNum(uint nodeNum);
bool factoryReset(); bool factoryReset();
@@ -131,6 +131,13 @@ class NodeDB
meshtastic_NodeInfoLite *getMeshNode(NodeNum n); meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
size_t getNumMeshNodes() { return *numMeshNodes; } 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: private:
/// Find a node in our DB, create an empty NodeInfoLite if missing /// Find a node in our DB, create an empty NodeInfoLite if missing
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n); meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
@@ -172,9 +179,6 @@ extern NodeDB nodeDB;
prefs.gps_update_interval = oneday prefs.gps_update_interval = oneday
prefs.is_power_saving = True prefs.is_power_saving = True
# allow up to five minutes for each new GPS lock attempt
prefs.gps_attempt_time = 300
*/ */
// Our delay functions check for this for times that should never expire // Our delay functions check for this for times that should never expire
@@ -185,18 +189,18 @@ extern NodeDB nodeDB;
#define ONE_DAY 24 * 60 * 60 #define ONE_DAY 24 * 60 * 60
#define default_gps_attempt_time IF_ROUTER(5 * 60, 15 * 60)
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60) #define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60) #define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
#define default_wait_bluetooth_secs IF_ROUTER(1, 60) #define default_wait_bluetooth_secs IF_ROUTER(1, 60)
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep #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_ls_secs IF_ROUTER(ONE_DAY, 5 * 60)
#define default_min_wake_secs 10 #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_address "mqtt.meshtastic.org"
#define default_mqtt_username "meshdev" #define default_mqtt_username "meshdev"
#define default_mqtt_password "large4cats" #define default_mqtt_password "large4cats"
#define default_mqtt_root "msh"
inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval) inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval)
{ {
@@ -212,6 +216,14 @@ inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t d
return defaultInterval * 1000; 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 /// Sometimes we will have Position objects that only have a time, so check for
/// valid lat/lon /// valid lat/lon
static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n) static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n)

View File

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

View File

@@ -294,6 +294,14 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag; fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
fromRadioScratch.moduleConfig.payload_variant.detection_sensor = moduleConfig.detection_sensor; fromRadioScratch.moduleConfig.payload_variant.detection_sensor = moduleConfig.detection_sensor;
break; 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;
case meshtastic_ModuleConfig_paxcounter_tag:
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag;
fromRadioScratch.moduleConfig.payload_variant.paxcounter = moduleConfig.paxcounter;
break;
default: default:
LOG_ERROR("Unknown module config type %d\n", config_state); LOG_ERROR("Unknown module config type %d\n", config_state);
} }
@@ -405,7 +413,7 @@ bool PhoneAPI::available()
if (nodeInfoForPhone.num == 0) { if (nodeInfoForPhone.num == 0) {
auto nextNode = nodeDB.readNextMeshNode(readIndex); auto nextNode = nodeDB.readNextMeshNode(readIndex);
if (nextNode) { 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 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(); RadioLibInterface::init();
if (power == 0)
power = POWER_DEFAULT;
if (power > MAX_POWER) // This chip has lower power limits than some if (power > MAX_POWER) // This chip has lower power limits than some
power = MAX_POWER; power = MAX_POWER;

View File

@@ -107,10 +107,25 @@ const RegionInfo regions[] = {
*/ */
RDEF(UA_868, 868.0f, 868.6f, 1, 0, 14, true, false, false), RDEF(UA_868, 868.0f, 868.6f, 1, 0, 14, true, false, false),
/*
Malaysia
433 - 435 MHz at 100mW, no restrictions.
https://www.mcmc.gov.my/skmmgovmy/media/General/pdf/Short-Range-Devices-Specification.pdf
*/
RDEF(MY_433, 433.0f, 435.0f, 100, 0, 20, true, false, false),
/*
Malaysia
919 - 923 Mhz at 500mW, no restrictions.
923 - 924 MHz at 500mW with 1% duty cycle OR frequency hopping.
Frequency hopping is used for 919 - 923 MHz.
https://www.mcmc.gov.my/skmmgovmy/media/General/pdf/Short-Range-Devices-Specification.pdf
*/
RDEF(MY_919, 919.0f, 924.0f, 100, 0, 27, true, true, false),
/* /*
2.4 GHZ WLAN Band equivalent. Only for SX128x chips. 2.4 GHZ WLAN Band equivalent. Only for SX128x chips.
*/ */
RDEF(LORA_24, 2400.0f, 2483.5f, 100, 0, 10, true, false, true), RDEF(LORA_24, 2400.0f, 2483.5f, 100, 0, 10, true, false, true),
/* /*
@@ -328,9 +343,9 @@ int RadioInterface::notifyDeepSleepCb(void *unused)
* djb2 by Dan Bernstein. * djb2 by Dan Bernstein.
* http://www.cse.yorku.ca/~oz/hash.html * http://www.cse.yorku.ca/~oz/hash.html
*/ */
unsigned long hash(const char *str) uint32_t hash(const char *str)
{ {
unsigned long hash = 5381; uint32_t hash = 5381;
int c; int c;
while ((c = *str++) != 0) while ((c = *str++) != 0)
@@ -384,27 +399,27 @@ void RadioInterface::applyModemConfig()
switch (loraConfig.modem_preset) { switch (loraConfig.modem_preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST: case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 5;
sf = 7; sf = 7;
break; break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 5;
sf = 8; sf = 8;
break; break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST: case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 5;
sf = 9; sf = 9;
break; break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 5;
sf = 10; sf = 10;
break; break;
default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal. default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal.
bw = (myRegion->wideLora) ? 812.5 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 5;
sf = 11; sf = 11;
break; break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE: case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
@@ -448,7 +463,9 @@ void RadioInterface::applyModemConfig()
power = myRegion->powerLimit; power = myRegion->powerLimit;
if (power == 0) 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 // Set final tx_power back onto config
loraConfig.tx_power = (int8_t)power; // cppcheck-suppress assignmentAddressToInteger loraConfig.tx_power = (int8_t)power; // cppcheck-suppress assignmentAddressToInteger
@@ -546,4 +563,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
sendingPacket = p; sendingPacket = p;
return p->encrypted.size + sizeof(PacketHeader); return p->encrypted.size + sizeof(PacketHeader);
} }

View File

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

View File

@@ -1,9 +1,6 @@
#include "RadioLibRF95.h" #include "RadioLibRF95.h"
#include "configuration.h" #include "configuration.h"
#define RF95_CHIP_VERSION 0x12
#define RF95_ALT_VERSION 0x11 // Supposedly some versions of the chip have id 0x11
// From datasheet but radiolib doesn't know anything about this // From datasheet but radiolib doesn't know anything about this
#define SX127X_REG_TCXO 0x4B #define SX127X_REG_TCXO 0x4B
@@ -13,9 +10,8 @@ int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_
uint8_t gain) uint8_t gain)
{ {
// execute common part // execute common part
int16_t state = SX127x::begin(RF95_CHIP_VERSION, syncWord, preambleLength); uint8_t rf95versions[2] = {0x12, 0x11};
if (state != RADIOLIB_ERR_NONE) int16_t state = SX127x::begin(rf95versions, sizeof(rf95versions), syncWord, preambleLength);
state = SX127x::begin(RF95_ALT_VERSION, syncWord, preambleLength);
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
// current limit was removed from module' ctor // current limit was removed from module' ctor
@@ -80,4 +76,4 @@ bool RadioLibRF95::isReceiving()
uint8_t RadioLibRF95::readReg(uint8_t addr) uint8_t RadioLibRF95::readReg(uint8_t addr)
{ {
return mod->SPIreadRegister(addr); return mod->SPIreadRegister(addr);
} }

View File

@@ -249,29 +249,12 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
bool shouldActuallyEncrypt = true;
if (moduleConfig.mqtt.enabled) { if (moduleConfig.mqtt.enabled) {
// check if we should send decrypted packets to mqtt
// truth table: LOG_INFO("Should encrypt MQTT?: %d\n", moduleConfig.mqtt.encryption_enabled);
/* 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);
// the packet is currently in a decrypted state. send it now if they want decrypted packets // the packet is currently in a decrypted state. send it now if they want decrypted packets
if (mqtt && !shouldActuallyEncrypt) if (mqtt && !moduleConfig.mqtt.encryption_enabled)
mqtt->onSend(*p, chIndex); mqtt->onSend(*p, chIndex);
} }
@@ -284,7 +267,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
if (moduleConfig.mqtt.enabled) { if (moduleConfig.mqtt.enabled) {
// the packet is now encrypted. // the packet is now encrypted.
// check if we should send encrypted packets to mqtt // check if we should send encrypted packets to mqtt
if (mqtt && shouldActuallyEncrypt) if (mqtt && moduleConfig.mqtt.encryption_enabled)
mqtt->onSend(*p, chIndex); mqtt->onSend(*p, chIndex);
} }
} }
@@ -316,6 +299,12 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_ALL_SKIP_DECODING) config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_ALL_SKIP_DECODING)
return false; return false;
if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY &&
!nodeDB.getMeshNode(p->from)->has_user) {
LOG_DEBUG("Node 0x%x not in NodeDB. Rebroadcast mode KNOWN_ONLY will ignore packet\n", p->from);
return false;
}
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag)
return true; // If packet was already decoded just return return true; // If packet was already decoded just return
@@ -359,7 +348,6 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
// LOG_DEBUG("\n\n**\n\nDecompressed length - %d \n", decompressed_len); // LOG_DEBUG("\n\n**\n\nDecompressed length - %d \n", decompressed_len);
memcpy(p->decoded.payload.bytes, decompressed_out, decompressed_len); memcpy(p->decoded.payload.bytes, decompressed_out, decompressed_len);
p->decoded.payload.size = decompressed_len;
// Switch the port from PortNum_TEXT_MESSAGE_COMPRESSED_APP to PortNum_TEXT_MESSAGE_APP // Switch the port from PortNum_TEXT_MESSAGE_COMPRESSED_APP to PortNum_TEXT_MESSAGE_APP
p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP; p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
@@ -383,7 +371,9 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
// If the packet is not yet encrypted, do so now // If the packet is not yet encrypted, do so now
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
// Only allow compression on the text message app. size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded);
// Only allow encryption on the text message app.
// TODO: Allow modules to opt into compression. // TODO: Allow modules to opt into compression.
if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) { if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) {
@@ -395,12 +385,17 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
int compressed_len; int compressed_len;
compressed_len = unishox2_compress_simple(original_payload, p->decoded.payload.size, compressed_out); compressed_len = unishox2_compress_simple(original_payload, p->decoded.payload.size, compressed_out);
LOG_DEBUG("Length - %d, compressed length - %d \n", p->decoded.payload.size, compressed_len); LOG_DEBUG("Original length - %d \n", p->decoded.payload.size);
LOG_DEBUG("Compressed length - %d \n", compressed_len);
LOG_DEBUG("Original message - %s \n", p->decoded.payload.bytes); LOG_DEBUG("Original message - %s \n", p->decoded.payload.bytes);
// If the compressed length is greater than or equal to the original size, don't use the compressed form // If the compressed length is greater than or equal to the original size, don't use the compressed form
if (compressed_len >= p->decoded.payload.size) { if (compressed_len >= p->decoded.payload.size) {
LOG_DEBUG("Not using compressing message.\n"); LOG_DEBUG("Not using compressing message.\n");
// Set the uncompressed payload variant anyway. Shouldn't hurt?
// p->decoded.which_payloadVariant = Data_payload_tag;
// Otherwise we use the compressor // Otherwise we use the compressor
} else { } else {
LOG_DEBUG("Using compressed message.\n"); LOG_DEBUG("Using compressed message.\n");
@@ -413,8 +408,6 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
} }
} }
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded);
if (numbytes > MAX_RHPACKETLEN) if (numbytes > MAX_RHPACKETLEN)
return meshtastic_Routing_Error_TOO_LARGE; return meshtastic_Routing_Error_TOO_LARGE;

View File

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

View File

@@ -2,8 +2,12 @@
#include "configuration.h" #include "configuration.h"
#include "error.h" #include "error.h"
#include "mesh/NodeDB.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 #ifndef SX126X_MAX_POWER
#define SX126X_MAX_POWER 22 #define SX126X_MAX_POWER 22
#endif #endif
@@ -22,24 +26,28 @@ SX126xInterface<T>::SX126xInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs
template <typename T> bool SX126xInterface<T>::init() template <typename T> bool SX126xInterface<T>::init()
{ {
#ifdef SX126X_POWER_EN #ifdef SX126X_POWER_EN
digitalWrite(SX126X_POWER_EN, HIGH);
pinMode(SX126X_POWER_EN, OUTPUT); pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, HIGH);
#endif #endif
#ifndef SX126X_E22 // FIXME: correct logic to default to not using TCXO if no voltage is specified for SX126X_DIO3_TCXO_VOLTAGE
float tcxoVoltage = 0; // None - we use an XTAL #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 #else
// Use DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575 float tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE;
float tcxoVoltage = 1.8; 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 #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? bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
RadioLibInterface::init(); RadioLibInterface::init();
if (power == 0) if (power > SX126X_MAX_POWER) // Clamp power to maximum defined level
power = SX126X_MAX_POWER;
if (power > SX126X_MAX_POWER) // This chip has lower power limits than some
power = SX126X_MAX_POWER; power = SX126X_MAX_POWER;
limitPower(); limitPower();
@@ -54,49 +62,56 @@ template <typename T> bool SX126xInterface<T>::init()
LOG_INFO("Bandwidth set to %f\n", bw); LOG_INFO("Bandwidth set to %f\n", bw);
LOG_INFO("Power output set to %d\n", power); LOG_INFO("Power output set to %d\n", power);
// current limit was removed from module' ctor // Overriding current limit
// override default value (60 mA) // (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); res = lora.setCurrentLimit(currentLimit);
LOG_DEBUG("Current limit set to %f\n", currentLimit); LOG_DEBUG("Current limit set to %f\n", currentLimit);
LOG_DEBUG("Current limit set result %d\n", res); LOG_DEBUG("Current limit set result %d\n", res);
#if defined(SX126X_E22) #ifdef SX126X_DIO2_AS_RF_SWITCH
// E22 Emulation explicitly requires DIO2 as RF switch, so set it to TRUE again for good measure. In case somebody defines LOG_DEBUG("Setting DIO2 as RF switch\n");
// SX126X_TX for an E22 Module bool dio2AsRfSwitch = true;
if (res == RADIOLIB_ERR_NONE) { #elif defined(ARCH_RASPBERRY_PI)
LOG_DEBUG("SX126X_E22 mode enabled. Setting DIO2 as RF Switch\n"); bool dio2AsRfSwitch = false;
res = lora.setDio2AsRfSwitch(true); 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 #endif
if (res == RADIOLIB_ERR_NONE) {
res = lora.setDio2AsRfSwitch(dio2AsRfSwitch);
}
#if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC) // 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
// If SX126X_TXEN is connected to the MCU, we are manually controlling RX and TX. // no effect
// But lora.begin (called above) sets Dio2 as RF switch control, which is not true here, so set it back to false. #ifndef SX126X_RXEN
if (res == RADIOLIB_ERR_NONE) { #define SX126X_RXEN RADIOLIB_NC
LOG_DEBUG("SX126X_TXEN pin defined. Setting RF Switch: RXEN=%i, TXEN=%i\n", SX126X_RXEN, SX126X_TXEN); LOG_DEBUG("SX126X_RXEN not defined, defaulting to RADIOLIB_NC\n");
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);
}
#endif #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) { if (config.lora.sx126x_rx_boosted_gain) {
uint16_t result = lora.setRxBoostedGainMode(true); 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 { } else {
uint16_t result = lora.setRxBoostedGainMode(false); 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 #if 0
@@ -152,11 +167,6 @@ template <typename T> bool SX126xInterface<T>::reconfigure()
if (err != RADIOLIB_ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING); RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
// TODO: Confirm gain registers are okay now
// err = lora.setRxGain(true);
// assert(err == RADIOLIB_ERR_NONE);
err = lora.setSyncWord(syncWord); err = lora.setSyncWord(syncWord);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
@@ -235,7 +245,7 @@ template <typename T> void SX126xInterface<T>::startReceive()
// We use a 16 bit preamble so this should save some power by letting radio sit in standby mostly. // We use a 16 bit preamble so this should save some power by letting radio sit in standby mostly.
// Furthermore, we need the PREAMBLE_DETECTED and HEADER_VALID IRQ flag to detect whether we are actively receiving // Furthermore, we need the PREAMBLE_DETECTED and HEADER_VALID IRQ flag to detect whether we are actively receiving
int err = lora.startReceiveDutyCycleAuto(preambleLength, 8, int err = lora.startReceiveDutyCycleAuto(preambleLength, 8,
RADIOLIB_SX126X_IRQ_RX_DEFAULT | RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED | RADIOLIB_SX126X_IRQ_RX_DEFAULT | RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED |
RADIOLIB_SX126X_IRQ_HEADER_VALID); RADIOLIB_SX126X_IRQ_HEADER_VALID);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
@@ -265,11 +275,11 @@ template <typename T> bool SX126xInterface<T>::isChannelActive()
/** Could we send right now (i.e. either not actively receiving or transmitting)? */ /** Could we send right now (i.e. either not actively receiving or transmitting)? */
template <typename T> bool SX126xInterface<T>::isActivelyReceiving() 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. // received and handled the interrupt for reading the packet/handling errors.
uint16_t irq = lora.getIrqStatus(); uint16_t irq = lora.getIrqStatus();
bool detected = (irq & (RADIOLIB_SX126X_IRQ_HEADER_VALID | RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED)); bool detected = (irq & (RADIOLIB_SX126X_IRQ_HEADER_VALID | RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED));
// Handle false detections // Handle false detections
if (detected) { if (detected) {
uint32_t now = millis(); uint32_t now = millis();
@@ -296,7 +306,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 // 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` // \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 setStandby(); // Stop any pending operations
// turn off TCXO if it was powered // turn off TCXO if it was powered
@@ -312,4 +322,4 @@ template <typename T> bool SX126xInterface<T>::sleep()
#endif #endif
return true; return true;
} }

View File

@@ -22,8 +22,8 @@ SX128xInterface<T>::SX128xInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs
template <typename T> bool SX128xInterface<T>::init() template <typename T> bool SX128xInterface<T>::init()
{ {
#ifdef SX128X_POWER_EN #ifdef SX128X_POWER_EN
digitalWrite(SX128X_POWER_EN, HIGH);
pinMode(SX128X_POWER_EN, OUTPUT); pinMode(SX128X_POWER_EN, OUTPUT);
digitalWrite(SX128X_POWER_EN, HIGH);
#endif #endif
#ifdef RF95_FAN_EN #ifdef RF95_FAN_EN
@@ -32,19 +32,16 @@ template <typename T> bool SX128xInterface<T>::init()
#endif #endif
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode
digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output
pinMode(SX128X_RXEN, OUTPUT); pinMode(SX128X_RXEN, OUTPUT);
digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output
#endif #endif
#if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC) #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
digitalWrite(SX128X_TXEN, LOW);
pinMode(SX128X_TXEN, OUTPUT); pinMode(SX128X_TXEN, OUTPUT);
digitalWrite(SX128X_TXEN, LOW);
#endif #endif
RadioLibInterface::init(); RadioLibInterface::init();
if (power == 0)
power = SX128X_MAX_POWER;
if (power > SX128X_MAX_POWER) // This chip has lower power limits than some if (power > SX128X_MAX_POWER) // This chip has lower power limits than some
power = SX128X_MAX_POWER; power = SX128X_MAX_POWER;
@@ -109,11 +106,6 @@ template <typename T> bool SX128xInterface<T>::reconfigure()
if (err != RADIOLIB_ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING); RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
// TODO: Confirm gain registers are okay now
// err = lora.setRxGain(true);
// assert(err == RADIOLIB_ERR_NONE);
err = lora.setSyncWord(syncWord); err = lora.setSyncWord(syncWord);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);

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/deviceonly.pb.h"
#include "mesh/generated/meshtastic/mesh.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; public:
static meshtastic_NodeInfo ConvertToNodeInfo(const meshtastic_NodeInfoLite *lite);
info.num = lite->num; static meshtastic_PositionLite ConvertToPositionLite(meshtastic_Position position);
info.snr = lite->snr; static meshtastic_Position ConvertToPosition(meshtastic_PositionLite lite);
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;
}

View File

@@ -27,6 +27,8 @@ template <class T> class TypedQueue
bool isEmpty() { return uxQueueMessagesWaiting(h) == 0; } bool isEmpty() { return uxQueueMessagesWaiting(h) == 0; }
int numUsed() { return uxQueueMessagesWaiting(h); }
/** euqueue a packet. Also, maxWait used to default to portMAX_DELAY, but we now want to callers to THINK about what blocking /** euqueue a packet. Also, maxWait used to default to portMAX_DELAY, but we now want to callers to THINK about what blocking
* they want */ * they want */
bool enqueue(T x, TickType_t maxWait) bool enqueue(T x, TickType_t maxWait)
@@ -80,6 +82,8 @@ template <class T> class TypedQueue
bool isEmpty() { return q.empty(); } bool isEmpty() { return q.empty(); }
int numUsed() { return q.size(); }
bool enqueue(T x, TickType_t maxWait = portMAX_DELAY) bool enqueue(T x, TickType_t maxWait = portMAX_DELAY)
{ {
if (reader) { if (reader) {

View File

@@ -15,6 +15,10 @@ void initApiServer(int port)
apiPort->init(); apiPort->init();
} }
} }
void deInitApiServer()
{
delete apiPort;
}
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : ServerAPI(_client) WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : ServerAPI(_client)
{ {
@@ -22,4 +26,4 @@ WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : ServerAPI(_client)
} }
WiFiServerPort::WiFiServerPort(int port) : APIServerPort(port) {} WiFiServerPort::WiFiServerPort(int port) : APIServerPort(port) {}
#endif #endif

View File

@@ -23,3 +23,4 @@ class WiFiServerPort : public APIServerPort<WiFiServerAPI, WiFiServer>
}; };
void initApiServer(int port = 4403); void initApiServer(int port = 4403);
void deInitApiServer();

View File

@@ -59,7 +59,9 @@ typedef enum _meshtastic_AdminMessage_ModuleConfigType {
/* TODO: REPLACE */ /* TODO: REPLACE */
meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG = 10, meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG = 10,
/* TODO: REPLACE */ /* TODO: REPLACE */
meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG = 11 meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG = 11,
/* TODO: REPLACE */
meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG = 12
} meshtastic_AdminMessage_ModuleConfigType; } meshtastic_AdminMessage_ModuleConfigType;
/* Struct definitions */ /* Struct definitions */
@@ -129,6 +131,9 @@ typedef struct _meshtastic_AdminMessage {
bool get_node_remote_hardware_pins_request; bool get_node_remote_hardware_pins_request;
/* Respond with the mesh's nodes with their available gpio pins for RemoteHardware module use */ /* Respond with the mesh's nodes with their available gpio pins for RemoteHardware module use */
meshtastic_NodeRemoteHardwarePinsResponse get_node_remote_hardware_pins_response; meshtastic_NodeRemoteHardwarePinsResponse get_node_remote_hardware_pins_response;
/* Enter (UF2) DFU mode
Only implemented on NRF52 currently */
bool enter_dfu_mode_request;
/* Set the owner for this node */ /* Set the owner for this node */
meshtastic_User set_owner; meshtastic_User set_owner;
/* Set channels (using the new API). /* Set channels (using the new API).
@@ -145,6 +150,8 @@ typedef struct _meshtastic_AdminMessage {
char set_canned_message_module_messages[201]; char set_canned_message_module_messages[201];
/* Set the ringtone for ExternalNotification. */ /* Set the ringtone for ExternalNotification. */
char set_ringtone_message[231]; 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 /* 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) */ This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */
bool begin_edit_settings; bool begin_edit_settings;
@@ -178,8 +185,8 @@ extern "C" {
#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_BLUETOOTH_CONFIG+1)) #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_MIN meshtastic_AdminMessage_ModuleConfigType_MQTT_CONFIG
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG #define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG+1)) #define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG+1))
#define meshtastic_AdminMessage_payload_variant_get_config_request_ENUMTYPE meshtastic_AdminMessage_ConfigType #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 #define meshtastic_AdminMessage_payload_variant_get_module_config_request_ENUMTYPE meshtastic_AdminMessage_ModuleConfigType
@@ -220,12 +227,14 @@ extern "C" {
#define meshtastic_AdminMessage_set_ham_mode_tag 18 #define meshtastic_AdminMessage_set_ham_mode_tag 18
#define meshtastic_AdminMessage_get_node_remote_hardware_pins_request_tag 19 #define meshtastic_AdminMessage_get_node_remote_hardware_pins_request_tag 19
#define meshtastic_AdminMessage_get_node_remote_hardware_pins_response_tag 20 #define meshtastic_AdminMessage_get_node_remote_hardware_pins_response_tag 20
#define meshtastic_AdminMessage_enter_dfu_mode_request_tag 21
#define meshtastic_AdminMessage_set_owner_tag 32 #define meshtastic_AdminMessage_set_owner_tag 32
#define meshtastic_AdminMessage_set_channel_tag 33 #define meshtastic_AdminMessage_set_channel_tag 33
#define meshtastic_AdminMessage_set_config_tag 34 #define meshtastic_AdminMessage_set_config_tag 34
#define meshtastic_AdminMessage_set_module_config_tag 35 #define meshtastic_AdminMessage_set_module_config_tag 35
#define meshtastic_AdminMessage_set_canned_message_module_messages_tag 36 #define meshtastic_AdminMessage_set_canned_message_module_messages_tag 36
#define meshtastic_AdminMessage_set_ringtone_message_tag 37 #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_begin_edit_settings_tag 64
#define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_commit_edit_settings_tag 65
#define meshtastic_AdminMessage_reboot_ota_seconds_tag 95 #define meshtastic_AdminMessage_reboot_ota_seconds_tag 95
@@ -256,12 +265,14 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_device_connection_status
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_ham_mode,set_ham_mode), 18) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_ham_mode,set_ham_mode), 18) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,get_node_remote_hardware_pins_request,get_node_remote_hardware_pins_request), 19) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,get_node_remote_hardware_pins_request,get_node_remote_hardware_pins_request), 19) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_node_remote_hardware_pins_response,get_node_remote_hardware_pins_response), 20) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_node_remote_hardware_pins_response,get_node_remote_hardware_pins_response), 20) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,enter_dfu_mode_request,enter_dfu_mode_request), 21) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_owner,set_owner), 32) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_owner,set_owner), 32) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 33) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 33) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \ 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, 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_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, 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,begin_edit_settings,begin_edit_settings), 64) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \
X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \

View File

@@ -30,11 +30,31 @@ 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. */ 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, meshtastic_Config_DeviceConfig_Role_REPEATER = 4,
/* Tracker device role /* 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, meshtastic_Config_DeviceConfig_Role_TRACKER = 5,
/* Sensor device role /* Sensor device role
Telemetry Mesh packets will be prioritized higher and sent more frequently by default. */ Telemetry Mesh packets will be prioritized higher and sent more frequently by default.
meshtastic_Config_DeviceConfig_Role_SENSOR = 6 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,
/* Client Hidden device role
Used for nodes that "only speak when spoken to"
Turns all of the routine broadcasts but allows for ad-hoc communication
Still rebroadcasts, but with local only rebroadcast mode (known meshes only)
Can be used for clandestine operation or to dramatically reduce airtime / power consumption */
meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN = 8,
/* Lost and Found device role
Used to automatically send a text message to the mesh
with the current position of the device on a frequent interval:
"I'm lost! Position: lat / long" */
meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND = 9
} meshtastic_Config_DeviceConfig_Role; } meshtastic_Config_DeviceConfig_Role;
/* Defines the device's behavior for how messages are rebroadcast */ /* Defines the device's behavior for how messages are rebroadcast */
@@ -47,7 +67,10 @@ typedef enum _meshtastic_Config_DeviceConfig_RebroadcastMode {
meshtastic_Config_DeviceConfig_RebroadcastMode_ALL_SKIP_DECODING = 1, meshtastic_Config_DeviceConfig_RebroadcastMode_ALL_SKIP_DECODING = 1,
/* Ignores observed messages from foreign meshes that are open or those which it cannot decrypt. /* Ignores observed messages from foreign meshes that are open or those which it cannot decrypt.
Only rebroadcasts message on the nodes local primary / secondary channels. */ Only rebroadcasts message on the nodes local primary / secondary channels. */
meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY = 2 meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY = 2,
/* Ignores observed messages from foreign meshes like LOCAL_ONLY,
but takes it step further by also ignoring messages from nodenums not in the node's known list (NodeDB) */
meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY = 3
} meshtastic_Config_DeviceConfig_RebroadcastMode; } meshtastic_Config_DeviceConfig_RebroadcastMode;
/* Bit field of boolean configuration options, indicating which optional /* Bit field of boolean configuration options, indicating which optional
@@ -178,7 +201,11 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode {
/* Ukraine 433mhz */ /* Ukraine 433mhz */
meshtastic_Config_LoRaConfig_RegionCode_UA_433 = 14, meshtastic_Config_LoRaConfig_RegionCode_UA_433 = 14,
/* Ukraine 868mhz */ /* Ukraine 868mhz */
meshtastic_Config_LoRaConfig_RegionCode_UA_868 = 15 meshtastic_Config_LoRaConfig_RegionCode_UA_868 = 15,
/* Malaysia 433mhz */
meshtastic_Config_LoRaConfig_RegionCode_MY_433 = 16,
/* Malaysia 919mhz */
meshtastic_Config_LoRaConfig_RegionCode_MY_919 = 17
} meshtastic_Config_LoRaConfig_RegionCode; } meshtastic_Config_LoRaConfig_RegionCode;
/* Standard predefined channel settings /* Standard predefined channel settings
@@ -258,10 +285,7 @@ typedef struct _meshtastic_Config_PositionConfig {
or zero for the default of once every 30 seconds or zero for the default of once every 30 seconds
or a very large value (maxint) to update only once at boot. */ or a very large value (maxint) to update only once at boot. */
uint32_t gps_update_interval; uint32_t gps_update_interval;
/* How long should we try to get our position during each gps_update_interval attempt? (in seconds) /* Deprecated in favor of using smart / regular broadcast intervals as implicit attempt time */
Or if zero, use the default of 30 seconds.
If we don't get a new gps fix in that time, the gps will be put into sleep until the next gps_update_rate
window. */
uint32_t gps_attempt_time; uint32_t gps_attempt_time;
/* Bit field of boolean configuration options for POSITION messages /* Bit field of boolean configuration options for POSITION messages
(bitwise OR of PositionFlags) */ (bitwise OR of PositionFlags) */
@@ -334,7 +358,7 @@ typedef struct _meshtastic_Config_NetworkConfig {
acquire an address via DHCP */ acquire an address via DHCP */
char wifi_ssid[33]; char wifi_ssid[33];
/* If set, will be use to authenticate to the named wifi */ /* 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` */ /* NTP server to use if WiFi is conneced, defaults to `0.pool.ntp.org` */
char ntp_server[33]; char ntp_server[33];
/* Enable Ethernet */ /* Enable Ethernet */
@@ -470,12 +494,12 @@ extern "C" {
/* Helper constants for enums */ /* Helper constants for enums */
#define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT #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_MAX meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_SENSOR+1)) #define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND+1))
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL #define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY #define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_RebroadcastMode)(meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY+1)) #define _meshtastic_Config_DeviceConfig_RebroadcastMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_RebroadcastMode)(meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY+1))
#define _meshtastic_Config_PositionConfig_PositionFlags_MIN meshtastic_Config_PositionConfig_PositionFlags_UNSET #define _meshtastic_Config_PositionConfig_PositionFlags_MIN meshtastic_Config_PositionConfig_PositionFlags_UNSET
#define _meshtastic_Config_PositionConfig_PositionFlags_MAX meshtastic_Config_PositionConfig_PositionFlags_SPEED #define _meshtastic_Config_PositionConfig_PositionFlags_MAX meshtastic_Config_PositionConfig_PositionFlags_SPEED
@@ -502,8 +526,8 @@ extern "C" {
#define _meshtastic_Config_DisplayConfig_DisplayMode_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DisplayMode)(meshtastic_Config_DisplayConfig_DisplayMode_COLOR+1)) #define _meshtastic_Config_DisplayConfig_DisplayMode_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DisplayMode)(meshtastic_Config_DisplayConfig_DisplayMode_COLOR+1))
#define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET #define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET
#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_UA_868 #define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_MY_919
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_UA_868+1)) #define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_MY_919+1))
#define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST #define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST
#define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE #define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE
@@ -781,10 +805,10 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
#define meshtastic_Config_DisplayConfig_size 28 #define meshtastic_Config_DisplayConfig_size 28
#define meshtastic_Config_LoRaConfig_size 77 #define meshtastic_Config_LoRaConfig_size 77
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20
#define meshtastic_Config_NetworkConfig_size 195 #define meshtastic_Config_NetworkConfig_size 196
#define meshtastic_Config_PositionConfig_size 60 #define meshtastic_Config_PositionConfig_size 60
#define meshtastic_Config_PowerConfig_size 40 #define meshtastic_Config_PowerConfig_size 40
#define meshtastic_Config_size 198 #define meshtastic_Config_size 199
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -313,10 +313,10 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define meshtastic_ChannelFile_size 638 #define meshtastic_ChannelFile_size 638
#define meshtastic_DeviceState_size 16854 #define meshtastic_DeviceState_size 17056
#define meshtastic_NodeInfoLite_size 151 #define meshtastic_NodeInfoLite_size 153
#define meshtastic_NodeRemoteHardwarePin_size 29 #define meshtastic_NodeRemoteHardwarePin_size 29
#define meshtastic_OEMStore_size 3218 #define meshtastic_OEMStore_size 3241
#define meshtastic_PositionLite_size 28 #define meshtastic_PositionLite_size 28
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -81,6 +81,9 @@ typedef struct _meshtastic_LocalModuleConfig {
/* The part of the config that is specific to the Detection Sensor module */ /* The part of the config that is specific to the Detection Sensor module */
bool has_detection_sensor; bool has_detection_sensor;
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor; meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
/* Paxcounter Config */
bool has_paxcounter;
meshtastic_ModuleConfig_PaxcounterConfig paxcounter;
} meshtastic_LocalModuleConfig; } meshtastic_LocalModuleConfig;
@@ -90,9 +93,9 @@ extern "C" {
/* Initializer values for message structs */ /* 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_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, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_default, false, meshtastic_ModuleConfig_DetectionSensorConfig_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, false, meshtastic_ModuleConfig_PaxcounterConfig_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_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, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_zero, false, meshtastic_ModuleConfig_DetectionSensorConfig_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, false, meshtastic_ModuleConfig_PaxcounterConfig_init_zero}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define meshtastic_LocalConfig_device_tag 1 #define meshtastic_LocalConfig_device_tag 1
@@ -116,6 +119,7 @@ extern "C" {
#define meshtastic_LocalModuleConfig_neighbor_info_tag 11 #define meshtastic_LocalModuleConfig_neighbor_info_tag 11
#define meshtastic_LocalModuleConfig_ambient_lighting_tag 12 #define meshtastic_LocalModuleConfig_ambient_lighting_tag 12
#define meshtastic_LocalModuleConfig_detection_sensor_tag 13 #define meshtastic_LocalModuleConfig_detection_sensor_tag 13
#define meshtastic_LocalModuleConfig_paxcounter_tag 14
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define meshtastic_LocalConfig_FIELDLIST(X, a) \ #define meshtastic_LocalConfig_FIELDLIST(X, a) \
@@ -150,7 +154,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, audio, 9) \
X(a, STATIC, OPTIONAL, MESSAGE, remote_hardware, 10) \ 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, ambient_lighting, 12) \
X(a, STATIC, OPTIONAL, MESSAGE, detection_sensor, 13) X(a, STATIC, OPTIONAL, MESSAGE, detection_sensor, 13) \
X(a, STATIC, OPTIONAL, MESSAGE, paxcounter, 14)
#define meshtastic_LocalModuleConfig_CALLBACK NULL #define meshtastic_LocalModuleConfig_CALLBACK NULL
#define meshtastic_LocalModuleConfig_DEFAULT NULL #define meshtastic_LocalModuleConfig_DEFAULT NULL
#define meshtastic_LocalModuleConfig_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig #define meshtastic_LocalModuleConfig_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
@@ -165,6 +170,7 @@ X(a, STATIC, OPTIONAL, MESSAGE, detection_sensor, 13)
#define meshtastic_LocalModuleConfig_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig #define meshtastic_LocalModuleConfig_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig
#define meshtastic_LocalModuleConfig_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig #define meshtastic_LocalModuleConfig_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
#define meshtastic_LocalModuleConfig_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig #define meshtastic_LocalModuleConfig_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
#define meshtastic_LocalModuleConfig_paxcounter_MSGTYPE meshtastic_ModuleConfig_PaxcounterConfig
extern const pb_msgdesc_t meshtastic_LocalConfig_msg; extern const pb_msgdesc_t meshtastic_LocalConfig_msg;
extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
@@ -174,8 +180,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg #define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define meshtastic_LocalConfig_size 463 #define meshtastic_LocalConfig_size 464
#define meshtastic_LocalModuleConfig_size 609 #define meshtastic_LocalModuleConfig_size 631
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -67,6 +67,10 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_STATION_G1 = 25, meshtastic_HardwareModel_STATION_G1 = 25,
/* RAK11310 (RP2040 + SX1262) */ /* RAK11310 (RP2040 + SX1262) */
meshtastic_HardwareModel_RAK11310 = 26, meshtastic_HardwareModel_RAK11310 = 26,
/* Makerfabs SenseLoRA Receiver (RP2040 + RFM96) */
meshtastic_HardwareModel_SENSELORA_RP2040 = 27,
/* Makerfabs SenseLoRA Industrial Monitor (ESP32-S3 + RFM96) */
meshtastic_HardwareModel_SENSELORA_S3 = 28,
/* --------------------------------------------------------------------------- /* ---------------------------------------------------------------------------
Less common/prototype boards listed here (needs one more byte over the air) Less common/prototype boards listed here (needs one more byte over the air)
--------------------------------------------------------------------------- */ --------------------------------------------------------------------------- */
@@ -113,6 +117,8 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_PICOMPUTER_S3 = 52, meshtastic_HardwareModel_PICOMPUTER_S3 = 52,
/* Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa */ /* Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa */
meshtastic_HardwareModel_HELTEC_HT62 = 53, 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. 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.
------------------------------------------------------------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------------------------------------------------------------ */
@@ -400,6 +406,8 @@ typedef struct _meshtastic_User {
If this user is a licensed operator, set this flag. If this user is a licensed operator, set this flag.
Also, "long_name" should be their licence number. */ Also, "long_name" should be their licence number. */
bool is_licensed; bool is_licensed;
/* Indicates that the user's role in the mesh */
meshtastic_Config_DeviceConfig_Role role;
} meshtastic_User; } meshtastic_User;
/* A message used in our Dynamic Source Routing protocol (RFC 4728 based) */ /* A message used in our Dynamic Source Routing protocol (RFC 4728 based) */
@@ -824,6 +832,7 @@ extern "C" {
#define meshtastic_Position_altitude_source_ENUMTYPE meshtastic_Position_AltSource #define meshtastic_Position_altitude_source_ENUMTYPE meshtastic_Position_AltSource
#define meshtastic_User_hw_model_ENUMTYPE meshtastic_HardwareModel #define meshtastic_User_hw_model_ENUMTYPE meshtastic_HardwareModel
#define meshtastic_User_role_ENUMTYPE meshtastic_Config_DeviceConfig_Role
#define meshtastic_Routing_variant_error_reason_ENUMTYPE meshtastic_Routing_Error #define meshtastic_Routing_variant_error_reason_ENUMTYPE meshtastic_Routing_Error
@@ -852,7 +861,7 @@ extern "C" {
/* Initializer values for message structs */ /* Initializer values for message structs */
#define meshtastic_Position_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Position_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0} #define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
#define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}} #define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}}
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
@@ -870,7 +879,7 @@ extern "C" {
#define meshtastic_Neighbor_init_default {0, 0, 0, 0} #define meshtastic_Neighbor_init_default {0, 0, 0, 0}
#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0} #define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
#define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0} #define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}} #define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}}
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
@@ -917,6 +926,7 @@ extern "C" {
#define meshtastic_User_macaddr_tag 4 #define meshtastic_User_macaddr_tag 4
#define meshtastic_User_hw_model_tag 5 #define meshtastic_User_hw_model_tag 5
#define meshtastic_User_is_licensed_tag 6 #define meshtastic_User_is_licensed_tag 6
#define meshtastic_User_role_tag 7
#define meshtastic_RouteDiscovery_route_tag 1 #define meshtastic_RouteDiscovery_route_tag 1
#define meshtastic_Routing_route_request_tag 1 #define meshtastic_Routing_route_request_tag 1
#define meshtastic_Routing_route_reply_tag 2 #define meshtastic_Routing_route_reply_tag 2
@@ -1045,7 +1055,8 @@ X(a, STATIC, SINGULAR, STRING, long_name, 2) \
X(a, STATIC, SINGULAR, STRING, short_name, 3) \ X(a, STATIC, SINGULAR, STRING, short_name, 3) \
X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4) \ X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4) \
X(a, STATIC, SINGULAR, UENUM, hw_model, 5) \ X(a, STATIC, SINGULAR, UENUM, hw_model, 5) \
X(a, STATIC, SINGULAR, BOOL, is_licensed, 6) X(a, STATIC, SINGULAR, BOOL, is_licensed, 6) \
X(a, STATIC, SINGULAR, UENUM, role, 7)
#define meshtastic_User_CALLBACK NULL #define meshtastic_User_CALLBACK NULL
#define meshtastic_User_DEFAULT NULL #define meshtastic_User_DEFAULT NULL
@@ -1278,13 +1289,13 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
#define meshtastic_MyNodeInfo_size 18 #define meshtastic_MyNodeInfo_size 18
#define meshtastic_NeighborInfo_size 258 #define meshtastic_NeighborInfo_size 258
#define meshtastic_Neighbor_size 22 #define meshtastic_Neighbor_size 22
#define meshtastic_NodeInfo_size 261 #define meshtastic_NodeInfo_size 263
#define meshtastic_Position_size 137 #define meshtastic_Position_size 137
#define meshtastic_QueueStatus_size 23 #define meshtastic_QueueStatus_size 23
#define meshtastic_RouteDiscovery_size 40 #define meshtastic_RouteDiscovery_size 40
#define meshtastic_Routing_size 42 #define meshtastic_Routing_size 42
#define meshtastic_ToRadio_size 504 #define meshtastic_ToRadio_size 504
#define meshtastic_User_size 77 #define meshtastic_User_size 79
#define meshtastic_Waypoint_size 165 #define meshtastic_Waypoint_size 165
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -24,6 +24,9 @@ PB_BIND(meshtastic_ModuleConfig_DetectionSensorConfig, meshtastic_ModuleConfig_D
PB_BIND(meshtastic_ModuleConfig_AudioConfig, meshtastic_ModuleConfig_AudioConfig, AUTO) PB_BIND(meshtastic_ModuleConfig_AudioConfig, meshtastic_ModuleConfig_AudioConfig, AUTO)
PB_BIND(meshtastic_ModuleConfig_PaxcounterConfig, meshtastic_ModuleConfig_PaxcounterConfig, AUTO)
PB_BIND(meshtastic_ModuleConfig_SerialConfig, meshtastic_ModuleConfig_SerialConfig, AUTO) PB_BIND(meshtastic_ModuleConfig_SerialConfig, meshtastic_ModuleConfig_SerialConfig, AUTO)

View File

@@ -170,6 +170,13 @@ typedef struct _meshtastic_ModuleConfig_AudioConfig {
uint8_t i2s_sck; uint8_t i2s_sck;
} meshtastic_ModuleConfig_AudioConfig; } meshtastic_ModuleConfig_AudioConfig;
/* Config for the Paxcounter Module */
typedef struct _meshtastic_ModuleConfig_PaxcounterConfig {
/* Enable the Paxcounter Module */
bool enabled;
uint32_t paxcounter_update_interval;
} meshtastic_ModuleConfig_PaxcounterConfig;
/* Serial Config */ /* Serial Config */
typedef struct _meshtastic_ModuleConfig_SerialConfig { typedef struct _meshtastic_ModuleConfig_SerialConfig {
/* Preferences for the SerialModule */ /* Preferences for the SerialModule */
@@ -232,6 +239,9 @@ typedef struct _meshtastic_ModuleConfig_ExternalNotificationConfig {
Default is 0 which means don't repeat at all. 60 would mean blink Default is 0 which means don't repeat at all. 60 would mean blink
and/or beep for 60 seconds */ and/or beep for 60 seconds */
uint16_t nag_timeout; 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; } meshtastic_ModuleConfig_ExternalNotificationConfig;
/* Store and Forward Module Config */ /* Store and Forward Module Config */
@@ -278,6 +288,15 @@ typedef struct _meshtastic_ModuleConfig_TelemetryConfig {
/* Interval in seconds of how often we should try to send our /* Interval in seconds of how often we should try to send our
air quality metrics to the mesh */ air quality metrics to the mesh */
uint32_t air_quality_interval; 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; } meshtastic_ModuleConfig_TelemetryConfig;
/* TODO: REPLACE */ /* TODO: REPLACE */
@@ -372,6 +391,8 @@ typedef struct _meshtastic_ModuleConfig {
meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting; meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting;
/* TODO: REPLACE */ /* TODO: REPLACE */
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor; meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
/* TODO: REPLACE */
meshtastic_ModuleConfig_PaxcounterConfig paxcounter;
} payload_variant; } payload_variant;
} meshtastic_ModuleConfig; } meshtastic_ModuleConfig;
@@ -408,6 +429,7 @@ extern "C" {
#define meshtastic_ModuleConfig_AudioConfig_bitrate_ENUMTYPE meshtastic_ModuleConfig_AudioConfig_Audio_Baud #define meshtastic_ModuleConfig_AudioConfig_bitrate_ENUMTYPE meshtastic_ModuleConfig_AudioConfig_Audio_Baud
#define meshtastic_ModuleConfig_SerialConfig_baud_ENUMTYPE meshtastic_ModuleConfig_SerialConfig_Serial_Baud #define meshtastic_ModuleConfig_SerialConfig_baud_ENUMTYPE meshtastic_ModuleConfig_SerialConfig_Serial_Baud
#define meshtastic_ModuleConfig_SerialConfig_mode_ENUMTYPE meshtastic_ModuleConfig_SerialConfig_Serial_Mode #define meshtastic_ModuleConfig_SerialConfig_mode_ENUMTYPE meshtastic_ModuleConfig_SerialConfig_Serial_Mode
@@ -430,11 +452,12 @@ extern "C" {
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0} #define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0}
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_default {0, 0, 0, 0, "", 0, 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_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_PaxcounterConfig_init_default {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_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_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {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_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_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
#define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN} #define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN}
@@ -444,11 +467,12 @@ extern "C" {
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0} #define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0}
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_zero {0, 0, 0, 0, "", 0, 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_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_PaxcounterConfig_init_zero {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_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_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {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_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_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0}
#define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN} #define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN}
@@ -480,6 +504,8 @@ extern "C" {
#define meshtastic_ModuleConfig_AudioConfig_i2s_sd_tag 5 #define meshtastic_ModuleConfig_AudioConfig_i2s_sd_tag 5
#define meshtastic_ModuleConfig_AudioConfig_i2s_din_tag 6 #define meshtastic_ModuleConfig_AudioConfig_i2s_din_tag 6
#define meshtastic_ModuleConfig_AudioConfig_i2s_sck_tag 7 #define meshtastic_ModuleConfig_AudioConfig_i2s_sck_tag 7
#define meshtastic_ModuleConfig_PaxcounterConfig_enabled_tag 1
#define meshtastic_ModuleConfig_PaxcounterConfig_paxcounter_update_interval_tag 2
#define meshtastic_ModuleConfig_SerialConfig_enabled_tag 1 #define meshtastic_ModuleConfig_SerialConfig_enabled_tag 1
#define meshtastic_ModuleConfig_SerialConfig_echo_tag 2 #define meshtastic_ModuleConfig_SerialConfig_echo_tag 2
#define meshtastic_ModuleConfig_SerialConfig_rxd_tag 3 #define meshtastic_ModuleConfig_SerialConfig_rxd_tag 3
@@ -502,6 +528,7 @@ extern "C" {
#define meshtastic_ModuleConfig_ExternalNotificationConfig_alert_bell_vibra_tag 12 #define meshtastic_ModuleConfig_ExternalNotificationConfig_alert_bell_vibra_tag 12
#define meshtastic_ModuleConfig_ExternalNotificationConfig_alert_bell_buzzer_tag 13 #define meshtastic_ModuleConfig_ExternalNotificationConfig_alert_bell_buzzer_tag 13
#define meshtastic_ModuleConfig_ExternalNotificationConfig_nag_timeout_tag 14 #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_enabled_tag 1
#define meshtastic_ModuleConfig_StoreForwardConfig_heartbeat_tag 2 #define meshtastic_ModuleConfig_StoreForwardConfig_heartbeat_tag 2
#define meshtastic_ModuleConfig_StoreForwardConfig_records_tag 3 #define meshtastic_ModuleConfig_StoreForwardConfig_records_tag 3
@@ -517,6 +544,9 @@ extern "C" {
#define meshtastic_ModuleConfig_TelemetryConfig_environment_display_fahrenheit_tag 5 #define meshtastic_ModuleConfig_TelemetryConfig_environment_display_fahrenheit_tag 5
#define meshtastic_ModuleConfig_TelemetryConfig_air_quality_enabled_tag 6 #define meshtastic_ModuleConfig_TelemetryConfig_air_quality_enabled_tag 6
#define meshtastic_ModuleConfig_TelemetryConfig_air_quality_interval_tag 7 #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_rotary1_enabled_tag 1
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2 #define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3 #define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3
@@ -551,6 +581,7 @@ extern "C" {
#define meshtastic_ModuleConfig_neighbor_info_tag 10 #define meshtastic_ModuleConfig_neighbor_info_tag 10
#define meshtastic_ModuleConfig_ambient_lighting_tag 11 #define meshtastic_ModuleConfig_ambient_lighting_tag 11
#define meshtastic_ModuleConfig_detection_sensor_tag 12 #define meshtastic_ModuleConfig_detection_sensor_tag 12
#define meshtastic_ModuleConfig_paxcounter_tag 13
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define meshtastic_ModuleConfig_FIELDLIST(X, a) \ #define meshtastic_ModuleConfig_FIELDLIST(X, a) \
@@ -565,7 +596,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,audio,payload_variant.audio)
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_variant.remote_hardware), 9) \ 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,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) X(a, STATIC, ONEOF, MESSAGE, (payload_variant,detection_sensor,payload_variant.detection_sensor), 12) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,paxcounter,payload_variant.paxcounter), 13)
#define meshtastic_ModuleConfig_CALLBACK NULL #define meshtastic_ModuleConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_DEFAULT NULL #define meshtastic_ModuleConfig_DEFAULT NULL
#define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig #define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
@@ -580,6 +612,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,detection_sensor,payload_var
#define meshtastic_ModuleConfig_payload_variant_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig #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_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
#define meshtastic_ModuleConfig_payload_variant_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig #define meshtastic_ModuleConfig_payload_variant_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
#define meshtastic_ModuleConfig_payload_variant_paxcounter_MSGTYPE meshtastic_ModuleConfig_PaxcounterConfig
#define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \ #define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
@@ -631,6 +664,12 @@ X(a, STATIC, SINGULAR, UINT32, i2s_sck, 7)
#define meshtastic_ModuleConfig_AudioConfig_CALLBACK NULL #define meshtastic_ModuleConfig_AudioConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_AudioConfig_DEFAULT NULL #define meshtastic_ModuleConfig_AudioConfig_DEFAULT NULL
#define meshtastic_ModuleConfig_PaxcounterConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
X(a, STATIC, SINGULAR, UINT32, paxcounter_update_interval, 2)
#define meshtastic_ModuleConfig_PaxcounterConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_PaxcounterConfig_DEFAULT NULL
#define meshtastic_ModuleConfig_SerialConfig_FIELDLIST(X, a) \ #define meshtastic_ModuleConfig_SerialConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
X(a, STATIC, SINGULAR, BOOL, echo, 2) \ X(a, STATIC, SINGULAR, BOOL, echo, 2) \
@@ -657,7 +696,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_message_buzzer, 11) \
X(a, STATIC, SINGULAR, BOOL, alert_bell_vibra, 12) \ X(a, STATIC, SINGULAR, BOOL, alert_bell_vibra, 12) \
X(a, STATIC, SINGULAR, BOOL, alert_bell_buzzer, 13) \ 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_CALLBACK NULL
#define meshtastic_ModuleConfig_ExternalNotificationConfig_DEFAULT NULL #define meshtastic_ModuleConfig_ExternalNotificationConfig_DEFAULT NULL
@@ -684,7 +724,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_screen_enabled, 4) \
X(a, STATIC, SINGULAR, BOOL, environment_display_fahrenheit, 5) \ X(a, STATIC, SINGULAR, BOOL, environment_display_fahrenheit, 5) \
X(a, STATIC, SINGULAR, BOOL, air_quality_enabled, 6) \ 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_CALLBACK NULL
#define meshtastic_ModuleConfig_TelemetryConfig_DEFAULT NULL #define meshtastic_ModuleConfig_TelemetryConfig_DEFAULT NULL
@@ -725,6 +768,7 @@ 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_NeighborInfoConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_DetectionSensorConfig_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_AudioConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_PaxcounterConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_SerialConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_SerialConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_ExternalNotificationConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_ExternalNotificationConfig_msg;
extern const pb_msgdesc_t meshtastic_ModuleConfig_StoreForwardConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_StoreForwardConfig_msg;
@@ -741,6 +785,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
#define meshtastic_ModuleConfig_NeighborInfoConfig_fields &meshtastic_ModuleConfig_NeighborInfoConfig_msg #define meshtastic_ModuleConfig_NeighborInfoConfig_fields &meshtastic_ModuleConfig_NeighborInfoConfig_msg
#define meshtastic_ModuleConfig_DetectionSensorConfig_fields &meshtastic_ModuleConfig_DetectionSensorConfig_msg #define meshtastic_ModuleConfig_DetectionSensorConfig_fields &meshtastic_ModuleConfig_DetectionSensorConfig_msg
#define meshtastic_ModuleConfig_AudioConfig_fields &meshtastic_ModuleConfig_AudioConfig_msg #define meshtastic_ModuleConfig_AudioConfig_fields &meshtastic_ModuleConfig_AudioConfig_msg
#define meshtastic_ModuleConfig_PaxcounterConfig_fields &meshtastic_ModuleConfig_PaxcounterConfig_msg
#define meshtastic_ModuleConfig_SerialConfig_fields &meshtastic_ModuleConfig_SerialConfig_msg #define meshtastic_ModuleConfig_SerialConfig_fields &meshtastic_ModuleConfig_SerialConfig_msg
#define meshtastic_ModuleConfig_ExternalNotificationConfig_fields &meshtastic_ModuleConfig_ExternalNotificationConfig_msg #define meshtastic_ModuleConfig_ExternalNotificationConfig_fields &meshtastic_ModuleConfig_ExternalNotificationConfig_msg
#define meshtastic_ModuleConfig_StoreForwardConfig_fields &meshtastic_ModuleConfig_StoreForwardConfig_msg #define meshtastic_ModuleConfig_StoreForwardConfig_fields &meshtastic_ModuleConfig_StoreForwardConfig_msg
@@ -755,14 +800,15 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
#define meshtastic_ModuleConfig_AudioConfig_size 19 #define meshtastic_ModuleConfig_AudioConfig_size 19
#define meshtastic_ModuleConfig_CannedMessageConfig_size 49 #define meshtastic_ModuleConfig_CannedMessageConfig_size 49
#define meshtastic_ModuleConfig_DetectionSensorConfig_size 44 #define meshtastic_ModuleConfig_DetectionSensorConfig_size 44
#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 40 #define meshtastic_ModuleConfig_ExternalNotificationConfig_size 42
#define meshtastic_ModuleConfig_MQTTConfig_size 222 #define meshtastic_ModuleConfig_MQTTConfig_size 222
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 8 #define meshtastic_ModuleConfig_NeighborInfoConfig_size 8
#define meshtastic_ModuleConfig_PaxcounterConfig_size 8
#define meshtastic_ModuleConfig_RangeTestConfig_size 10 #define meshtastic_ModuleConfig_RangeTestConfig_size 10
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
#define meshtastic_ModuleConfig_SerialConfig_size 28 #define meshtastic_ModuleConfig_SerialConfig_size 28
#define meshtastic_ModuleConfig_StoreForwardConfig_size 22 #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_ModuleConfig_size 225
#define meshtastic_RemoteHardwarePin_size 21 #define meshtastic_RemoteHardwarePin_size 21

View File

@@ -0,0 +1,12 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.7 */
#include "meshtastic/paxcount.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(meshtastic_Paxcount, meshtastic_Paxcount, AUTO)

View File

@@ -0,0 +1,57 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.7 */
#ifndef PB_MESHTASTIC_MESHTASTIC_PAXCOUNT_PB_H_INCLUDED
#define PB_MESHTASTIC_MESHTASTIC_PAXCOUNT_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
/* TODO: REPLACE */
typedef struct _meshtastic_Paxcount {
/* seen Wifi devices */
uint32_t wifi;
/* Seen BLE devices */
uint32_t ble;
/* Uptime in seconds */
uint32_t uptime;
} meshtastic_Paxcount;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define meshtastic_Paxcount_init_default {0, 0, 0}
#define meshtastic_Paxcount_init_zero {0, 0, 0}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_Paxcount_wifi_tag 1
#define meshtastic_Paxcount_ble_tag 2
#define meshtastic_Paxcount_uptime_tag 3
/* Struct field encoding specification for nanopb */
#define meshtastic_Paxcount_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, wifi, 1) \
X(a, STATIC, SINGULAR, UINT32, ble, 2) \
X(a, STATIC, SINGULAR, UINT32, uptime, 3)
#define meshtastic_Paxcount_CALLBACK NULL
#define meshtastic_Paxcount_DEFAULT NULL
extern const pb_msgdesc_t meshtastic_Paxcount_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_Paxcount_fields &meshtastic_Paxcount_msg
/* Maximum encoded size of messages (where known) */
#define meshtastic_Paxcount_size 18
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -69,7 +69,8 @@ typedef enum _meshtastic_PortNum {
NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate. 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. */ This marker comes from the 'moduleConfig.audio.bitrate' enum minus one. */
meshtastic_PortNum_AUDIO_APP = 9, meshtastic_PortNum_AUDIO_APP = 9,
/* Same as Text Message but originating from Detection Sensor Module. */ /* 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, meshtastic_PortNum_DETECTION_SENSOR_APP = 10,
/* Provides a 'ping' service that replies to any packet it receives. /* Provides a 'ping' service that replies to any packet it receives.
Also serves as a small example module. Also serves as a small example module.
@@ -78,6 +79,9 @@ typedef enum _meshtastic_PortNum {
/* Used for the python IP tunnel feature /* Used for the python IP tunnel feature
ENCODING: IP Packet. Handled by the python API, firmware ignores this one and pases on. */ ENCODING: IP Packet. Handled by the python API, firmware ignores this one and pases on. */
meshtastic_PortNum_IP_TUNNEL_APP = 33, meshtastic_PortNum_IP_TUNNEL_APP = 33,
/* Paxcounter lib included in the firmware
ENCODING: protobuf */
meshtastic_PortNum_PAXCOUNTER_APP = 34,
/* Provides a hardware serial interface to send and receive from the Meshtastic network. /* Provides a hardware serial interface to send and receive from the Meshtastic network.
Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network. network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
@@ -90,7 +94,8 @@ typedef enum _meshtastic_PortNum {
ENCODING: Protobuf */ ENCODING: Protobuf */
meshtastic_PortNum_STORE_FORWARD_APP = 65, meshtastic_PortNum_STORE_FORWARD_APP = 65,
/* Optional port for messages for the range test module. /* 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, meshtastic_PortNum_RANGE_TEST_APP = 66,
/* Provides a format to send and receive telemetry data from the Meshtastic network. /* Provides a format to send and receive telemetry data from the Meshtastic network.
Maintained by Charles Crossan (crossan007) : crossan007@gmail.com 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_EnvironmentMetrics, meshtastic_EnvironmentMetrics, AUTO)
PB_BIND(meshtastic_PowerMetrics, meshtastic_PowerMetrics, AUTO)
PB_BIND(meshtastic_AirQualityMetrics, meshtastic_AirQualityMetrics, AUTO) PB_BIND(meshtastic_AirQualityMetrics, meshtastic_AirQualityMetrics, AUTO)

View File

@@ -39,7 +39,9 @@ typedef enum _meshtastic_TelemetrySensorType {
/* High accuracy temperature and humidity */ /* High accuracy temperature and humidity */
meshtastic_TelemetrySensorType_SHT31 = 12, meshtastic_TelemetrySensorType_SHT31 = 12,
/* PM2.5 air quality sensor */ /* 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; } meshtastic_TelemetrySensorType;
/* Struct definitions */ /* Struct definitions */
@@ -65,12 +67,28 @@ typedef struct _meshtastic_EnvironmentMetrics {
float barometric_pressure; float barometric_pressure;
/* Gas resistance in MOhm measured */ /* Gas resistance in MOhm measured */
float gas_resistance; float gas_resistance;
/* Voltage measured */ /* Voltage measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) */
float voltage; float voltage;
/* Current measured */ /* Current measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) */
float current; float current;
} meshtastic_EnvironmentMetrics; } 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 */ /* Air quality metrics */
typedef struct _meshtastic_AirQualityMetrics { typedef struct _meshtastic_AirQualityMetrics {
/* Concentration Units Standard PM1.0 */ /* Concentration Units Standard PM1.0 */
@@ -111,6 +129,8 @@ typedef struct _meshtastic_Telemetry {
meshtastic_EnvironmentMetrics environment_metrics; meshtastic_EnvironmentMetrics environment_metrics;
/* Air quality metrics */ /* Air quality metrics */
meshtastic_AirQualityMetrics air_quality_metrics; meshtastic_AirQualityMetrics air_quality_metrics;
/* Power Metrics */
meshtastic_PowerMetrics power_metrics;
} variant; } variant;
} meshtastic_Telemetry; } meshtastic_Telemetry;
@@ -121,8 +141,9 @@ extern "C" {
/* Helper constants for enums */ /* Helper constants for enums */
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_PMSA003I #define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_INA3221
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_PMSA003I+1)) #define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_INA3221+1))
@@ -132,10 +153,12 @@ extern "C" {
/* Initializer values for message structs */ /* Initializer values for message structs */
#define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0} #define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0}
#define meshtastic_EnvironmentMetrics_init_default {0, 0, 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_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_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}}
#define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0} #define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0}
#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 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_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}} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}}
@@ -150,6 +173,12 @@ extern "C" {
#define meshtastic_EnvironmentMetrics_gas_resistance_tag 4 #define meshtastic_EnvironmentMetrics_gas_resistance_tag 4
#define meshtastic_EnvironmentMetrics_voltage_tag 5 #define meshtastic_EnvironmentMetrics_voltage_tag 5
#define meshtastic_EnvironmentMetrics_current_tag 6 #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_pm10_standard_tag 1
#define meshtastic_AirQualityMetrics_pm25_standard_tag 2 #define meshtastic_AirQualityMetrics_pm25_standard_tag 2
#define meshtastic_AirQualityMetrics_pm100_standard_tag 3 #define meshtastic_AirQualityMetrics_pm100_standard_tag 3
@@ -166,6 +195,7 @@ extern "C" {
#define meshtastic_Telemetry_device_metrics_tag 2 #define meshtastic_Telemetry_device_metrics_tag 2
#define meshtastic_Telemetry_environment_metrics_tag 3 #define meshtastic_Telemetry_environment_metrics_tag 3
#define meshtastic_Telemetry_air_quality_metrics_tag 4 #define meshtastic_Telemetry_air_quality_metrics_tag 4
#define meshtastic_Telemetry_power_metrics_tag 5
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define meshtastic_DeviceMetrics_FIELDLIST(X, a) \ #define meshtastic_DeviceMetrics_FIELDLIST(X, a) \
@@ -186,6 +216,16 @@ X(a, STATIC, SINGULAR, FLOAT, current, 6)
#define meshtastic_EnvironmentMetrics_CALLBACK NULL #define meshtastic_EnvironmentMetrics_CALLBACK NULL
#define meshtastic_EnvironmentMetrics_DEFAULT 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) \ #define meshtastic_AirQualityMetrics_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, pm10_standard, 1) \ X(a, STATIC, SINGULAR, UINT32, pm10_standard, 1) \
X(a, STATIC, SINGULAR, UINT32, pm25_standard, 2) \ X(a, STATIC, SINGULAR, UINT32, pm25_standard, 2) \
@@ -206,21 +246,25 @@ X(a, STATIC, SINGULAR, UINT32, particles_100um, 12)
X(a, STATIC, SINGULAR, FIXED32, time, 1) \ 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,device_metrics,variant.device_metrics), 2) \
X(a, STATIC, ONEOF, MESSAGE, (variant,environment_metrics,variant.environment_metrics), 3) \ 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_CALLBACK NULL
#define meshtastic_Telemetry_DEFAULT NULL #define meshtastic_Telemetry_DEFAULT NULL
#define meshtastic_Telemetry_variant_device_metrics_MSGTYPE meshtastic_DeviceMetrics #define meshtastic_Telemetry_variant_device_metrics_MSGTYPE meshtastic_DeviceMetrics
#define meshtastic_Telemetry_variant_environment_metrics_MSGTYPE meshtastic_EnvironmentMetrics #define meshtastic_Telemetry_variant_environment_metrics_MSGTYPE meshtastic_EnvironmentMetrics
#define meshtastic_Telemetry_variant_air_quality_metrics_MSGTYPE meshtastic_AirQualityMetrics #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_DeviceMetrics_msg;
extern const pb_msgdesc_t meshtastic_EnvironmentMetrics_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_AirQualityMetrics_msg;
extern const pb_msgdesc_t meshtastic_Telemetry_msg; extern const pb_msgdesc_t meshtastic_Telemetry_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ /* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_DeviceMetrics_fields &meshtastic_DeviceMetrics_msg #define meshtastic_DeviceMetrics_fields &meshtastic_DeviceMetrics_msg
#define meshtastic_EnvironmentMetrics_fields &meshtastic_EnvironmentMetrics_msg #define meshtastic_EnvironmentMetrics_fields &meshtastic_EnvironmentMetrics_msg
#define meshtastic_PowerMetrics_fields &meshtastic_PowerMetrics_msg
#define meshtastic_AirQualityMetrics_fields &meshtastic_AirQualityMetrics_msg #define meshtastic_AirQualityMetrics_fields &meshtastic_AirQualityMetrics_msg
#define meshtastic_Telemetry_fields &meshtastic_Telemetry_msg #define meshtastic_Telemetry_fields &meshtastic_Telemetry_msg
@@ -228,6 +272,7 @@ extern const pb_msgdesc_t meshtastic_Telemetry_msg;
#define meshtastic_AirQualityMetrics_size 72 #define meshtastic_AirQualityMetrics_size 72
#define meshtastic_DeviceMetrics_size 21 #define meshtastic_DeviceMetrics_size 21
#define meshtastic_EnvironmentMetrics_size 30 #define meshtastic_EnvironmentMetrics_size 30
#define meshtastic_PowerMetrics_size 30
#define meshtastic_Telemetry_size 79 #define meshtastic_Telemetry_size 79
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -5,7 +5,7 @@
#include "main.h" #include "main.h"
#include "mesh/http/ContentHelper.h" #include "mesh/http/ContentHelper.h"
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "mqtt/JSON.h" #include "mqtt/JSON.h"
#include "power.h" #include "power.h"
#include "sleep.h" #include "sleep.h"
@@ -144,8 +144,8 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res)
/* /*
For documentation, see: For documentation, see:
https://meshtastic.org/docs/developers/device/http-api https://meshtastic.org/docs/development/device/http-api
https://meshtastic.org/docs/developers/device/device-api https://meshtastic.org/docs/development/device/client-api
*/ */
// Get access to the parameters // Get access to the parameters
@@ -194,8 +194,8 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
/* /*
For documentation, see: For documentation, see:
https://meshtastic.org/docs/developers/device/http-api https://meshtastic.org/docs/development/device/http-api
https://meshtastic.org/docs/developers/device/device-api https://meshtastic.org/docs/development/device/client-api
*/ */
res->setHeader("Content-Type", "application/x-protobuf"); res->setHeader("Content-Type", "application/x-protobuf");

View File

@@ -1,5 +1,4 @@
#pragma once #pragma once
void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer); void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer);
// Declare some handler functions for the various URLs on the server // Declare some handler functions for the various URLs on the server
@@ -34,4 +33,4 @@ class HttpAPI : public PhoneAPI
protected: protected:
/// Check the current underlying physical link to see if the client is currently connected /// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override { return true; } // FIXME, be smarter about this virtual bool checkIsConnected() override { return true; } // FIXME, be smarter about this
}; };

View File

@@ -1,6 +1,6 @@
#include "mesh/http/ContentHelper.h" #include "mesh/http/ContentHelper.h"
//#include <Arduino.h> // #include <Arduino.h>
//#include "main.h" // #include "main.h"
void replaceAll(std::string &str, const std::string &from, const std::string &to) void replaceAll(std::string &str, const std::string &from, const std::string &to)
{ {

View File

@@ -2,7 +2,7 @@
#include "NodeDB.h" #include "NodeDB.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "main.h" #include "main.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "sleep.h" #include "sleep.h"
#include <HTTPBodyParser.hpp> #include <HTTPBodyParser.hpp>
#include <HTTPMultipartBodyParser.hpp> #include <HTTPMultipartBodyParser.hpp>
@@ -210,4 +210,4 @@ void initWebServer()
} else { } else {
LOG_ERROR("Web Servers Failed! ;-( \n"); LOG_ERROR("Web Servers Failed! ;-( \n");
} }
} }

View File

@@ -1,17 +1,20 @@
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h" #include "RTC.h"
#include "concurrency/Periodic.h" #include "concurrency/Periodic.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "mesh/api/WiFiServerAPI.h" #include "mesh/api/WiFiServerAPI.h"
#include "mesh/http/WebServer.h"
#include "mqtt/MQTT.h" #include "mqtt/MQTT.h"
#include "target_specific.h" #include "target_specific.h"
#include <ESPmDNS.h>
#include <WiFi.h> #include <WiFi.h>
#include <WiFiUdp.h> #include <WiFiUdp.h>
#ifdef ARCH_ESP32
#include "mesh/http/WebServer.h"
#include <ESPmDNS.h>
#include <esp_wifi.h> #include <esp_wifi.h>
static void WiFiEvent(WiFiEvent_t event);
#endif
#ifndef DISABLE_NTP #ifndef DISABLE_NTP
#include <NTPClient.h> #include <NTPClient.h>
@@ -19,8 +22,6 @@
using namespace concurrency; using namespace concurrency;
static void WiFiEvent(WiFiEvent_t event);
// NTP // NTP
WiFiUDP ntpUDP; WiFiUDP ntpUDP;
@@ -37,91 +38,21 @@ bool APStartupComplete = 0;
unsigned long lastrun_ntp = 0; unsigned long lastrun_ntp = 0;
bool needReconnect = true; // If we create our reconnector, run it once at the beginning bool needReconnect = true; // If we create our reconnector, run it once at the beginning
bool isReconnecting = false; // If we are currently reconnecting
WiFiUDP syslogClient; WiFiUDP syslogClient;
Syslog syslog(syslogClient); Syslog syslog(syslogClient);
Periodic *wifiReconnect; Periodic *wifiReconnect;
static int32_t reconnectWiFi()
{
const char *wifiName = config.network.wifi_ssid;
const char *wifiPsw = config.network.wifi_psk;
if (config.network.wifi_enabled && needReconnect) {
if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL;
needReconnect = false;
// Make sure we clear old connection credentials
WiFi.disconnect(false, true);
LOG_INFO("Reconnecting to WiFi access point %s\n", wifiName);
delay(5000);
if (!WiFi.isConnected()) {
WiFi.begin(wifiName, wifiPsw);
}
}
#ifndef DISABLE_NTP
if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours
LOG_DEBUG("Updating NTP time from %s\n", config.network.ntp_server);
if (timeClient.update()) {
LOG_DEBUG("NTP Request Success - Setting RTCQualityNTP if needed\n");
struct timeval tv;
tv.tv_sec = timeClient.getEpochTime();
tv.tv_usec = 0;
perhapsSetRTC(RTCQualityNTP, &tv);
lastrun_ntp = millis();
} else {
LOG_DEBUG("NTP Update failed\n");
}
}
#endif
if (config.network.wifi_enabled && !WiFi.isConnected()) {
return 1000; // check once per second
} else {
return 300000; // every 5 minutes
}
}
bool isWifiAvailable()
{
if (config.network.wifi_enabled && (config.network.wifi_ssid[0])) {
return true;
} else {
return false;
}
}
// Disable WiFi
void deinitWifi()
{
LOG_INFO("WiFi deinit\n");
if (isWifiAvailable()) {
WiFi.disconnect(true);
WiFi.mode(WIFI_MODE_NULL);
LOG_INFO("WiFi Turned Off\n");
// WiFi.printDiag(Serial);
}
}
static void onNetworkConnected() static void onNetworkConnected()
{ {
if (!APStartupComplete) { if (!APStartupComplete) {
// Start web server // Start web server
LOG_INFO("Starting network services\n"); LOG_INFO("Starting network services\n");
#ifdef ARCH_ESP32
// start mdns // start mdns
if (!MDNS.begin("Meshtastic")) { if (!MDNS.begin("Meshtastic")) {
LOG_ERROR("Error setting up MDNS responder!\n"); LOG_ERROR("Error setting up MDNS responder!\n");
@@ -131,6 +62,9 @@ static void onNetworkConnected()
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);
MDNS.addService("https", "tcp", 443); MDNS.addService("https", "tcp", 443);
} }
#else // ESP32 handles this in WiFiEvent
LOG_INFO("Obtained IP address: %s\n", WiFi.localIP().toString().c_str());
#endif
#ifndef DISABLE_NTP #ifndef DISABLE_NTP
LOG_INFO("Starting NTP time client\n"); LOG_INFO("Starting NTP time client\n");
@@ -158,7 +92,9 @@ static void onNetworkConnected()
syslog.enable(); syslog.enable();
} }
#ifdef ARCH_ESP32
initWebServer(); initWebServer();
#endif
initApiServer(); initApiServer();
APStartupComplete = true; APStartupComplete = true;
@@ -169,6 +105,96 @@ static void onNetworkConnected()
mqtt->reconnect(); mqtt->reconnect();
} }
static int32_t reconnectWiFi()
{
const char *wifiName = config.network.wifi_ssid;
const char *wifiPsw = config.network.wifi_psk;
if (config.network.wifi_enabled && needReconnect) {
if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL;
needReconnect = false;
isReconnecting = true;
// Make sure we clear old connection credentials
#ifdef ARCH_ESP32
WiFi.disconnect(false, true);
#else
WiFi.disconnect(false);
#endif
LOG_INFO("Reconnecting to WiFi access point %s\n", wifiName);
delay(5000);
if (!WiFi.isConnected()) {
WiFi.begin(wifiName, wifiPsw);
}
isReconnecting = false;
}
#ifndef DISABLE_NTP
if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours
LOG_DEBUG("Updating NTP time from %s\n", config.network.ntp_server);
if (timeClient.update()) {
LOG_DEBUG("NTP Request Success - Setting RTCQualityNTP if needed\n");
struct timeval tv;
tv.tv_sec = timeClient.getEpochTime();
tv.tv_usec = 0;
perhapsSetRTC(RTCQualityNTP, &tv);
lastrun_ntp = millis();
} else {
LOG_DEBUG("NTP Update failed\n");
}
}
#endif
if (config.network.wifi_enabled && !WiFi.isConnected()) {
#ifdef ARCH_RP2040 // (ESP32 handles this in WiFiEvent)
/* If APStartupComplete, but we're not connected, try again.
Shouldn't try again before APStartupComplete. */
needReconnect = APStartupComplete;
#endif
return 1000; // check once per second
} else {
#ifdef ARCH_RP2040
onNetworkConnected(); // will only do anything once
#endif
return 300000; // every 5 minutes
}
}
bool isWifiAvailable()
{
if (config.network.wifi_enabled && (config.network.wifi_ssid[0])) {
return true;
} else {
return false;
}
}
// Disable WiFi
void deinitWifi()
{
LOG_INFO("WiFi deinit\n");
if (isWifiAvailable()) {
#ifdef ARCH_ESP32
WiFi.disconnect(true, false);
#else
WiFi.disconnect(true);
#endif
WiFi.mode(WIFI_OFF);
LOG_INFO("WiFi Turned Off\n");
// WiFi.printDiag(Serial);
}
}
// Startup WiFi // Startup WiFi
bool initWifi() bool initWifi()
{ {
@@ -177,10 +203,10 @@ bool initWifi()
const char *wifiName = config.network.wifi_ssid; const char *wifiName = config.network.wifi_ssid;
const char *wifiPsw = config.network.wifi_psk; const char *wifiPsw = config.network.wifi_psk;
createSSLCert(); #ifndef ARCH_RP2040
createSSLCert(); // For WebServer
esp_wifi_set_storage(WIFI_STORAGE_RAM); // Disable flash storage for WiFi credentials esp_wifi_set_storage(WIFI_STORAGE_RAM); // Disable flash storage for WiFi credentials
#endif
if (!*wifiPsw) // Treat empty password as no password if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL; wifiPsw = NULL;
@@ -189,17 +215,17 @@ bool initWifi()
getMacAddr(dmac); getMacAddr(dmac);
snprintf(ourHost, sizeof(ourHost), "Meshtastic-%02x%02x", dmac[4], dmac[5]); snprintf(ourHost, sizeof(ourHost), "Meshtastic-%02x%02x", dmac[4], dmac[5]);
WiFi.mode(WIFI_MODE_STA); WiFi.mode(WIFI_STA);
WiFi.setHostname(ourHost); WiFi.setHostname(ourHost);
WiFi.onEvent(WiFiEvent);
WiFi.setAutoReconnect(true);
WiFi.setSleep(false);
if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC && if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC &&
config.network.ipv4_config.ip != 0) { config.network.ipv4_config.ip != 0) {
WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.gateway, config.network.ipv4_config.subnet, WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.gateway, config.network.ipv4_config.subnet,
config.network.ipv4_config.dns, config.network.ipv4_config.dns);
config.network.ipv4_config.dns); // Wifi wants two DNS servers... set both to the same value
} }
#ifndef ARCH_RP2040
WiFi.onEvent(WiFiEvent);
WiFi.setAutoReconnect(true);
WiFi.setSleep(false);
// This is needed to improve performance. // This is needed to improve performance.
esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving
@@ -218,7 +244,7 @@ bool initWifi()
wifiDisconnectReason = info.wifi_sta_disconnected.reason; wifiDisconnectReason = info.wifi_sta_disconnected.reason;
}, },
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED); WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
#endif
LOG_DEBUG("JOINING WIFI soon: ssid=%s\n", wifiName); LOG_DEBUG("JOINING WIFI soon: ssid=%s\n", wifiName);
wifiReconnect = new Periodic("WifiConnect", reconnectWiFi); wifiReconnect = new Periodic("WifiConnect", reconnectWiFi);
} }
@@ -229,6 +255,7 @@ bool initWifi()
} }
} }
#ifdef ARCH_ESP32
// Called by the Espressif SDK to // Called by the Espressif SDK to
static void WiFiEvent(WiFiEvent_t event) static void WiFiEvent(WiFiEvent_t event)
{ {
@@ -253,27 +280,31 @@ static void WiFiEvent(WiFiEvent_t event)
break; break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
LOG_INFO("Disconnected from WiFi access point\n"); LOG_INFO("Disconnected from WiFi access point\n");
WiFi.disconnect(false, true); if (!isReconnecting) {
syslog.disable(); WiFi.disconnect(false, true);
needReconnect = true; syslog.disable();
wifiReconnect->setIntervalFromNow(1000); needReconnect = true;
wifiReconnect->setIntervalFromNow(1000);
}
break; break;
case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
LOG_INFO("Authentication mode of access point has changed\n"); LOG_INFO("Authentication mode of access point has changed\n");
break; break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP: case ARDUINO_EVENT_WIFI_STA_GOT_IP:
LOG_INFO("Obtained IP address: ", WiFi.localIPv6()); LOG_INFO("Obtained IP address: %s\n", WiFi.localIP().toString().c_str());
onNetworkConnected(); onNetworkConnected();
break; break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP6: case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
LOG_INFO("Obtained IP6 address: %s", WiFi.localIPv6()); LOG_INFO("Obtained IP6 address: %s\n", WiFi.localIPv6().toString().c_str());
break; break;
case ARDUINO_EVENT_WIFI_STA_LOST_IP: case ARDUINO_EVENT_WIFI_STA_LOST_IP:
LOG_INFO("Lost IP address and IP address is reset to 0\n"); LOG_INFO("Lost IP address and IP address is reset to 0\n");
WiFi.disconnect(false, true); if (!isReconnecting) {
syslog.disable(); WiFi.disconnect(false, true);
needReconnect = true; syslog.disable();
wifiReconnect->setIntervalFromNow(1000); needReconnect = true;
wifiReconnect->setIntervalFromNow(1000);
}
break; break;
case ARDUINO_EVENT_WPS_ER_SUCCESS: case ARDUINO_EVENT_WPS_ER_SUCCESS:
LOG_INFO("WiFi Protected Setup (WPS): succeeded in enrollee mode\n"); LOG_INFO("WiFi Protected Setup (WPS): succeeded in enrollee mode\n");
@@ -369,8 +400,9 @@ static void WiFiEvent(WiFiEvent_t event)
break; break;
} }
} }
#endif
uint8_t getWifiDisconnectReason() uint8_t getWifiDisconnectReason()
{ {
return wifiDisconnectReason; return wifiDisconnectReason;
} }

View File

@@ -5,7 +5,7 @@
#include <Arduino.h> #include <Arduino.h>
#include <functional> #include <functional>
#ifdef ARCH_ESP32 #if defined(HAS_WIFI) && !defined(ARCH_PORTDUINO)
#include <WiFi.h> #include <WiFi.h>
#endif #endif
@@ -19,4 +19,4 @@ void deinitWifi();
bool isWifiAvailable(); bool isWifiAvailable();
uint8_t getWifiDisconnectReason(); uint8_t getWifiDisconnectReason();

View File

@@ -39,10 +39,11 @@
*/ */
char *strnstr(const char *s, const char *find, size_t slen) char *strnstr(const char *s, const char *find, size_t slen)
{ {
char c, sc; char c;
size_t len;
if ((c = *find++) != '\0') { if ((c = *find++) != '\0') {
char sc;
size_t len;
len = strlen(find); len = strlen(find);
do { do {
do { do {

View File

@@ -182,6 +182,18 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
} }
break; break;
} }
case meshtastic_AdminMessage_remove_by_nodenum_tag: {
LOG_INFO("Client is receiving a remove_nodenum command.\n");
nodeDB.removeNodeByNum(r->remove_by_nodenum);
break;
}
case meshtastic_AdminMessage_enter_dfu_mode_request_tag: {
LOG_INFO("Client is requesting to enter DFU mode.\n");
#if defined(ARCH_NRF52) || defined(ARCH_RP2040)
enterDfuMode();
#endif
break;
}
#ifdef ARCH_PORTDUINO #ifdef ARCH_PORTDUINO
case meshtastic_AdminMessage_exit_simulator_tag: case meshtastic_AdminMessage_exit_simulator_tag:
LOG_INFO("Exiting simulator\n"); LOG_INFO("Exiting simulator\n");
@@ -378,6 +390,16 @@ void AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
moduleConfig.has_detection_sensor = true; moduleConfig.has_detection_sensor = true;
moduleConfig.detection_sensor = c.payload_variant.detection_sensor; moduleConfig.detection_sensor = c.payload_variant.detection_sensor;
break; 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;
case meshtastic_ModuleConfig_paxcounter_tag:
LOG_INFO("Setting module config: Paxcounter\n");
moduleConfig.has_paxcounter = true;
moduleConfig.paxcounter = c.payload_variant.paxcounter;
break;
} }
saveChanges(SEGMENT_MODULECONFIG); saveChanges(SEGMENT_MODULECONFIG);
@@ -523,6 +545,16 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag; 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; res.get_module_config_response.payload_variant.detection_sensor = moduleConfig.detection_sensor;
break; 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;
case meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG:
LOG_INFO("Getting module config: Paxcounter\n");
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag;
res.get_module_config_response.payload_variant.paxcounter = moduleConfig.paxcounter;
break;
} }
// NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior. // NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior.
@@ -606,12 +638,12 @@ void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &r
#if HAS_BLUETOOTH #if HAS_BLUETOOTH
conn.has_bluetooth = true; conn.has_bluetooth = true;
conn.bluetooth.pin = config.bluetooth.fixed_pin; conn.bluetooth.pin = config.bluetooth.fixed_pin;
#endif
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
conn.bluetooth.is_connected = nimbleBluetooth->isConnected(); conn.bluetooth.is_connected = nimbleBluetooth->isConnected();
conn.bluetooth.rssi = nimbleBluetooth->getRssi(); conn.bluetooth.rssi = nimbleBluetooth->getRssi();
#elif defined(ARCH_NRF52) #elif defined(ARCH_NRF52)
conn.bluetooth.is_connected = nrf52Bluetooth->isConnected(); conn.bluetooth.is_connected = nrf52Bluetooth->isConnected();
#endif
#endif #endif
conn.has_serial = true; // No serial-less devices conn.has_serial = true; // No serial-less devices
conn.serial.is_connected = powerFSM.getState() == &stateSERIAL; conn.serial.is_connected = powerFSM.getState() == &stateSERIAL;
@@ -676,11 +708,11 @@ void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p)
channels.onConfigChanged(); channels.onConfigChanged();
service.reloadOwner(false); 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) AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_APP, &meshtastic_AdminMessage_msg)
{ {
// restrict to the admin channel for rx // restrict to the admin channel for rx
boundChannel = Channels::adminChannel; boundChannel = Channels::adminChannel;
} }

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "ProtobufModule.h" #include "ProtobufModule.h"
#ifdef ARCH_ESP32 #if HAS_WIFI
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#endif #endif
/** /**
@@ -50,4 +50,4 @@ class AdminModule : public ProtobufModule<meshtastic_AdminMessage>
void reboot(int32_t seconds); void reboot(int32_t seconds);
}; };
extern AdminModule *adminModule; extern AdminModule *adminModule;

View File

@@ -1,6 +1,10 @@
#include "configuration.h" #include "configuration.h"
#if ARCH_RASPBERRY_PI
#include "PortduinoGlue.h"
#endif
#if HAS_SCREEN #if HAS_SCREEN
#include "CannedMessageModule.h" #include "CannedMessageModule.h"
#include "Channels.h"
#include "FSCommon.h" #include "FSCommon.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
@@ -138,17 +142,23 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
// source at all) // source at all)
return 0; return 0;
} }
if (this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
return 0; // Ignore input while sending
}
bool validEvent = false; bool validEvent = false;
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP)) { if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP)) {
// LOG_DEBUG("Canned message event UP\n"); if (this->messagesCount > 0) {
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_UP; // LOG_DEBUG("Canned message event UP\n");
validEvent = true; this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_UP;
validEvent = true;
}
} }
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN)) { if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN)) {
// LOG_DEBUG("Canned message event DOWN\n"); if (this->messagesCount > 0) {
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_DOWN; // LOG_DEBUG("Canned message event DOWN\n");
validEvent = true; this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_DOWN;
validEvent = true;
}
} }
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) { if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) {
LOG_DEBUG("Canned message event Select\n"); LOG_DEBUG("Canned message event Select\n");
@@ -163,9 +173,14 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
} }
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) { if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) {
LOG_DEBUG("Canned message event Cancel\n"); LOG_DEBUG("Canned message event Cancel\n");
// emulate a timeout. Same result UIFrameEvent e = {false, true};
this->lastTouchMillis = 0; e.frameChanged = true;
validEvent = true; this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext
this->cursor = 0;
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
this->notifyObservers(&e);
} }
if ((event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK)) || if ((event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK)) ||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) || (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
@@ -175,10 +190,10 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
if (!event->kbchar) { if (!event->kbchar) {
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) { if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
this->payload = 0xb4; this->payload = 0xb4;
this->destSelect = true; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) { } else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
this->payload = 0xb7; this->payload = 0xb7;
this->destSelect = true; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
} }
} else { } else {
// pass the pressed key // pass the pressed key
@@ -212,16 +227,21 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
if (validEvent) { if (validEvent) {
// Let runOnce to be called immediately. // Let runOnce to be called immediately.
setIntervalFromNow(0); if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) {
setIntervalFromNow(0); // on fast keypresses, this isn't fast enough.
} else {
runOnce();
}
} }
return 0; return 0;
} }
void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantReplies) void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const char *message, bool wantReplies)
{ {
meshtastic_MeshPacket *p = allocDataPacket(); meshtastic_MeshPacket *p = allocDataPacket();
p->to = dest; p->to = dest;
p->channel = channel;
p->want_ack = true; p->want_ack = true;
p->decoded.payload.size = strlen(message); p->decoded.payload.size = strlen(message);
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size); memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
@@ -233,7 +253,9 @@ void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantR
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes); LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
service.sendToMesh(p); service.sendToMesh(
p, RX_SRC_LOCAL,
true); // send to mesh, cc to phone. Even if there's no phone connected, this stores the message to match ACKs
} }
int32_t CannedMessageModule::runOnce() int32_t CannedMessageModule::runOnce()
@@ -244,14 +266,15 @@ int32_t CannedMessageModule::runOnce()
} }
// LOG_DEBUG("Check status\n"); // LOG_DEBUG("Check status\n");
UIFrameEvent e = {false, true}; UIFrameEvent e = {false, true};
if (this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) { if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) ||
(this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED)) {
// TODO: might have some feedback of sendig state // TODO: might have some feedback of sendig state
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
e.frameChanged = true; e.frameChanged = true;
this->currentMessageIndex = -1; this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
this->destSelect = false; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
this->notifyObservers(&e); this->notifyObservers(&e);
} else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) && } else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) &&
((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) { ((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) {
@@ -261,13 +284,13 @@ int32_t CannedMessageModule::runOnce()
this->currentMessageIndex = -1; this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
this->destSelect = false; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
this->notifyObservers(&e); this->notifyObservers(&e);
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) { } else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) {
if (this->payload == CANNED_MESSAGE_RUN_STATE_FREETEXT) { if (this->payload == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
if (this->freetext.length() > 0) { if (this->freetext.length() > 0) {
sendText(this->dest, this->freetext.c_str(), true); sendText(this->dest, indexChannels[this->channel], this->freetext.c_str(), true);
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE; this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
} else { } else {
LOG_DEBUG("Reset message is empty.\n"); LOG_DEBUG("Reset message is empty.\n");
@@ -279,7 +302,7 @@ int32_t CannedMessageModule::runOnce()
powerFSM.trigger(EVENT_PRESS); powerFSM.trigger(EVENT_PRESS);
return INT32_MAX; return INT32_MAX;
} else { } else {
sendText(NODENUM_BROADCAST, this->messages[this->currentMessageIndex], true); sendText(NODENUM_BROADCAST, channels.getPrimaryIndex(), this->messages[this->currentMessageIndex], true);
} }
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE; this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
} else { } else {
@@ -291,7 +314,7 @@ int32_t CannedMessageModule::runOnce()
this->currentMessageIndex = -1; this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
this->destSelect = false; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
this->notifyObservers(&e); this->notifyObservers(&e);
return 2000; return 2000;
} else if ((this->runState != CANNED_MESSAGE_RUN_STATE_FREETEXT) && (this->currentMessageIndex == -1)) { } else if ((this->runState != CANNED_MESSAGE_RUN_STATE_FREETEXT) && (this->currentMessageIndex == -1)) {
@@ -304,7 +327,7 @@ int32_t CannedMessageModule::runOnce()
this->currentMessageIndex = getPrevIndex(); this->currentMessageIndex = getPrevIndex();
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
this->destSelect = false; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE; this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
LOG_DEBUG("MOVE UP (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage()); LOG_DEBUG("MOVE UP (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
} }
@@ -313,14 +336,14 @@ int32_t CannedMessageModule::runOnce()
this->currentMessageIndex = this->getNextIndex(); this->currentMessageIndex = this->getNextIndex();
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
this->destSelect = false; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE; this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
LOG_DEBUG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage()); LOG_DEBUG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
} }
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT || this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) { } else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT || this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) {
switch (this->payload) { switch (this->payload) {
case 0xb4: // left case 0xb4: // left
if (this->destSelect) { if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NODE) {
size_t numMeshNodes = nodeDB.getNumMeshNodes(); size_t numMeshNodes = nodeDB.getNumMeshNodes();
if (this->dest == NODENUM_BROADCAST) { if (this->dest == NODENUM_BROADCAST) {
this->dest = nodeDB.getNodeNum(); this->dest = nodeDB.getNodeNum();
@@ -335,6 +358,19 @@ int32_t CannedMessageModule::runOnce()
if (this->dest == nodeDB.getNodeNum()) { if (this->dest == nodeDB.getNodeNum()) {
this->dest = NODENUM_BROADCAST; this->dest = NODENUM_BROADCAST;
} }
} else if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL) {
for (unsigned int i = 0; i < channels.getNumChannels(); i++) {
if ((channels.getByIndex(i).role == meshtastic_Channel_Role_SECONDARY) ||
(channels.getByIndex(i).role == meshtastic_Channel_Role_PRIMARY)) {
indexChannels[numChannels] = i;
numChannels++;
}
}
if (this->channel == 0) {
this->channel = numChannels - 1;
} else {
this->channel--;
}
} else { } else {
if (this->cursor > 0) { if (this->cursor > 0) {
this->cursor--; this->cursor--;
@@ -342,7 +378,7 @@ int32_t CannedMessageModule::runOnce()
} }
break; break;
case 0xb7: // right case 0xb7: // right
if (this->destSelect) { if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NODE) {
size_t numMeshNodes = nodeDB.getNumMeshNodes(); size_t numMeshNodes = nodeDB.getNumMeshNodes();
if (this->dest == NODENUM_BROADCAST) { if (this->dest == NODENUM_BROADCAST) {
this->dest = nodeDB.getNodeNum(); this->dest = nodeDB.getNodeNum();
@@ -357,6 +393,19 @@ int32_t CannedMessageModule::runOnce()
if (this->dest == nodeDB.getNodeNum()) { if (this->dest == nodeDB.getNodeNum()) {
this->dest = NODENUM_BROADCAST; this->dest = NODENUM_BROADCAST;
} }
} else if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL) {
for (unsigned int i = 0; i < channels.getNumChannels(); i++) {
if ((channels.getByIndex(i).role == meshtastic_Channel_Role_SECONDARY) ||
(channels.getByIndex(i).role == meshtastic_Channel_Role_PRIMARY)) {
indexChannels[numChannels] = i;
numChannels++;
}
}
if (this->channel == numChannels - 1) {
this->channel = 0;
} else {
this->channel++;
}
} else { } else {
if (this->cursor < this->freetext.length()) { if (this->cursor < this->freetext.length()) {
this->cursor++; this->cursor++;
@@ -381,10 +430,12 @@ int32_t CannedMessageModule::runOnce()
} }
break; break;
case 0x09: // tab case 0x09: // tab
if (this->destSelect) { if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL) {
this->destSelect = false; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
} else if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NODE) {
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL;
} else { } else {
this->destSelect = true; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
} }
break; break;
case 0xb4: // left case 0xb4: // left
@@ -483,7 +534,18 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
{ {
char buffer[50]; char buffer[50];
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) { if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
String displayString;
if (this->ack) {
displayString = "Delivered to\n%s";
} else {
displayString = "Delivery failed\nto %s";
}
display->drawStringf(display->getWidth() / 2 + x, 0 + y + 12, buffer, displayString,
cannedMessageModule->getNodeName(this->incoming));
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
display->setTextAlignment(TEXT_ALIGN_CENTER); display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM); display->setFont(FONT_MEDIUM);
display->drawString(display->getWidth() / 2 + x, 0 + y + 12, "Sending..."); display->drawString(display->getWidth() / 2 + x, 0 + y + 12, "Sending...");
@@ -494,19 +556,39 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
if (this->destSelect) { if (this->destSelect != CANNED_MESSAGE_DESTINATION_TYPE_NONE) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK); display->setColor(BLACK);
display->drawStringf(1 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
} }
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest)); switch (this->destSelect) {
// used chars right aligned case CANNED_MESSAGE_DESTINATION_TYPE_NODE:
uint16_t charsLeft = display->drawStringf(1 + x, 0 + y, buffer, "To: >%s<@%s", cannedMessageModule->getNodeName(this->dest),
meshtastic_Constants_DATA_PAYLOAD_LEN - this->freetext.length() - (moduleConfig.canned_message.send_bell ? 1 : 0); channels.getName(indexChannels[this->channel]));
snprintf(buffer, sizeof(buffer), "%d left", charsLeft); display->drawStringf(0 + x, 0 + y, buffer, "To: >%s<@%s", cannedMessageModule->getNodeName(this->dest),
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer); channels.getName(indexChannels[this->channel]));
if (this->destSelect) { break;
display->drawString(x + display->getWidth() - display->getStringWidth(buffer) - 1, y + 0, buffer); case CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL:
display->drawStringf(1 + x, 0 + y, buffer, "To: %s@>%s<", cannedMessageModule->getNodeName(this->dest),
channels.getName(indexChannels[this->channel]));
display->drawStringf(0 + x, 0 + y, buffer, "To: %s@>%s<", cannedMessageModule->getNodeName(this->dest),
channels.getName(indexChannels[this->channel]));
break;
default:
if (display->getWidth() > 128) {
display->drawStringf(0 + x, 0 + y, buffer, "To: %s@%s", cannedMessageModule->getNodeName(this->dest),
channels.getName(indexChannels[this->channel]));
} else {
display->drawStringf(0 + x, 0 + y, buffer, "To: %.5s@%.5s", cannedMessageModule->getNodeName(this->dest),
channels.getName(indexChannels[this->channel]));
}
break;
}
// used chars right aligned, only when not editing the destination
if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NONE) {
uint16_t charsLeft =
meshtastic_Constants_DATA_PAYLOAD_LEN - this->freetext.length() - (moduleConfig.canned_message.send_bell ? 1 : 0);
snprintf(buffer, sizeof(buffer), "%d left", charsLeft);
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer);
} }
display->setColor(WHITE); display->setColor(WHITE);
display->drawStringMaxWidth( display->drawStringMaxWidth(
@@ -546,6 +628,27 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
} }
} }
ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
{
if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP) {
// look for a request_id
if (mp.decoded.request_id != 0) {
UIFrameEvent e = {false, true};
e.frameChanged = true;
this->runState = CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED;
this->incoming = service.getNodenumFromRequestId(mp.decoded.request_id);
meshtastic_Routing decoded = meshtastic_Routing_init_default;
pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_Routing_fields, &decoded);
this->ack = decoded.error_reason == meshtastic_Routing_Error_NONE;
this->notifyObservers(&e);
// run the next time 2 seconds later
setIntervalFromNow(2000);
}
}
return ProcessMessage::CONTINUE;
}
void CannedMessageModule::loadProtoForModule() void CannedMessageModule::loadProtoForModule()
{ {
if (!nodeDB.loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, if (!nodeDB.loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,
@@ -650,4 +753,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
return result; return result;
} }
#endif #endif

View File

@@ -9,11 +9,18 @@ enum cannedMessageModuleRunState {
CANNED_MESSAGE_RUN_STATE_ACTIVE, CANNED_MESSAGE_RUN_STATE_ACTIVE,
CANNED_MESSAGE_RUN_STATE_FREETEXT, CANNED_MESSAGE_RUN_STATE_FREETEXT,
CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE, CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE,
CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED,
CANNED_MESSAGE_RUN_STATE_ACTION_SELECT, CANNED_MESSAGE_RUN_STATE_ACTION_SELECT,
CANNED_MESSAGE_RUN_STATE_ACTION_UP, CANNED_MESSAGE_RUN_STATE_ACTION_UP,
CANNED_MESSAGE_RUN_STATE_ACTION_DOWN, CANNED_MESSAGE_RUN_STATE_ACTION_DOWN,
}; };
enum cannedMessageDestinationType {
CANNED_MESSAGE_DESTINATION_TYPE_NONE,
CANNED_MESSAGE_DESTINATION_TYPE_NODE,
CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL
};
#define CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT 50 #define CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT 50
/** /**
* Sum of CannedMessageModuleConfig part sizes. * Sum of CannedMessageModuleConfig part sizes.
@@ -37,19 +44,33 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
const char *getMessageByIndex(int index); const char *getMessageByIndex(int index);
const char *getNodeName(NodeNum node); const char *getNodeName(NodeNum node);
bool shouldDraw(); bool shouldDraw();
void eventUp(); // void eventUp();
void eventDown(); // void eventDown();
void eventSelect(); // void eventSelect();
void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response); void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
void handleSetCannedMessageModuleMessages(const char *from_msg); void handleSetCannedMessageModuleMessages(const char *from_msg);
String drawWithCursor(String text, int cursor); String drawWithCursor(String text, int cursor);
/*
-Override the wantPacket method. We need the Routing Messages to look for ACKs.
*/
virtual bool wantPacket(const meshtastic_MeshPacket *p) override
{
switch (p->decoded.portnum) {
case meshtastic_PortNum_TEXT_MESSAGE_APP:
case meshtastic_PortNum_ROUTING_APP:
return true;
default:
return false;
}
}
protected: protected:
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
void sendText(NodeNum dest, const char *message, bool wantReplies); void sendText(NodeNum dest, ChannelIndex channel, const char *message, bool wantReplies);
int splitConfiguredMessages(); int splitConfiguredMessages();
int getNextIndex(); int getNextIndex();
@@ -63,6 +84,12 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
meshtastic_AdminMessage *request, meshtastic_AdminMessage *request,
meshtastic_AdminMessage *response) override; meshtastic_AdminMessage *response) override;
/** Called to handle a particular incoming message
* @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered
* for it
*/
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
void loadProtoForModule(); void loadProtoForModule();
bool saveProtoForModule(); bool saveProtoForModule();
@@ -72,9 +99,14 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
cannedMessageModuleRunState runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; cannedMessageModuleRunState runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
char payload = 0x00; char payload = 0x00;
unsigned int cursor = 0; unsigned int cursor = 0;
String freetext = ""; // Text Buffer for Freetext Editor String freetext = ""; // Text Buffer for Freetext Editor
bool destSelect = false; // Freetext Editor Mode
NodeNum dest = NODENUM_BROADCAST; NodeNum dest = NODENUM_BROADCAST;
ChannelIndex channel = 0;
cannedMessageDestinationType destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
uint8_t numChannels = 0;
ChannelIndex indexChannels[MAX_NUM_CHANNELS] = {0};
NodeNum incoming = NODENUM_BROADCAST;
bool ack = false; // True means ACK, false means NAK (error_reason != NONE)
char messageStore[CANNED_MESSAGE_MODULE_MESSAGES_SIZE + 1]; char messageStore[CANNED_MESSAGE_MODULE_MESSAGES_SIZE + 1];
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT]; char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
@@ -83,4 +115,4 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
}; };
extern CannedMessageModule *cannedMessageModule; extern CannedMessageModule *cannedMessageModule;
#endif #endif

View File

@@ -28,6 +28,12 @@ int32_t DetectionSensorModule::runOnce()
return disable(); return disable();
if (firstTime) { 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 // This is the first time the OSThread library has called this function, so do some setup
firstTime = false; firstTime = false;
if (moduleConfig.detection_sensor.monitor_pin > 0) { if (moduleConfig.detection_sensor.monitor_pin > 0) {

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