Compare commits

...
Author SHA1 Message Date
Ben Meadorsandmverch67 7f7c5cbd62 Triple GPS state (#3157)
* Triple state GPS refactoring

* Skip probe

* Move GPS toggle into the GPSThread

* Consolidate

* make all happy (including me)

* corrected screen texts

* NOT_PRESENT guard in main.cpp

---------

Co-authored-by: mverch67 <manuel.verch@gmx.de>
2024-02-01 15:24:39 -06:00
GUVWAFandBen Meadors 0c0a3c4b55 Fix: mark packet sent to MQTT as ACKed only after we sent it out via LoRa (#3155)
* Fix: mark packet via MQTT as ACKed only after we sent it out via LoRa

* Don't need to check for broadcast, DMs also get implicit ACKs

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-31 14:04:52 -06:00
github-actions[bot]andthebentern bf762bc58d [create-pull-request] automated change (#3156)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-31 13:47:17 -06:00
Ben Meadors 84e578323e Update version.properties 2024-01-31 13:46:48 -06:00
Ben Meadors bdbe42dfd0 Update version.properties 2024-01-31 12:58:04 -06:00
github-actions[bot]andthebentern 4f64c4f7b9 [create-pull-request] automated change (#3154)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-30 20:01:00 -06:00
Jonathan Bennett af5ac32048 Re-order GPS check to eliminate TOO old message (#3152) 2024-01-30 17:44:08 -06:00
9586c68c65 GPS updates (#3142)
* Portduino multiple logging levels

* Fixes based on GPSFan work

* Fix derped logic

* Correct size field for AID message

* Reformat to add comments, beginning of GPS rework

* Update PM2 message for Neo-6

* Correct ECO mode logic as ECO mode is only for Neo-6

* Cleanup ubx.h add a few more comments

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-30 17:38:31 -06:00
ca45888f3e feat(variants): Add support for TXCO on TLORA_V2_1_6 devices (#3124)
* feat(variants): Add support for TXCO on TLORA_V2_1_6 devices

* chore: remove long comment

* feat(variants): Add tlora-v2-1-1_6-tcxo to build matrix

* feat(variants): Use RADIOLIB_NC as DIO1 pin for tlora_v2_1_16 with TXCO

* Use generic naming scheme, add variant to build envs

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: code8buster <20384924+code8buster@users.noreply.github.com>
2024-01-30 07:06:47 -06:00
Andre K 1e4ecea6fc update to Meshtastic_nRF52_factory_erase_v2 (#3146) 2024-01-29 20:07:09 -06:00
code8busterandBen Meadors d1ea589757 Allow NRF52 ADC overrides; begin simplifying analog battery logic (#3134)
* Isolate esp32 adc logic gymnastics, try simplifying getBattVoltage

* Set sense resolution for pico platforms

* try silencing cppcheck when variant has no battery pin

* ADC channel for esp-idf calibration

* Missed an rp2040 device

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-29 06:14:21 -06:00
GUVWAFandBen Meadors af52dcecdf Restrict MQTT JSON downlink messages (#3141)
Channel needs to be named "mqtt"
"from" field should be set to the node number of the transmitter

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-29 06:13:56 -06:00
Ben Meadors 0ae4622393 Admin message to delete file (#3144)
* Protos

* Delete file admin message
2024-01-29 06:10:48 -06:00
Jonathan Bennett a49740cd56 Adds i2c device configuration to native (#3143) 2024-01-28 20:15:29 -06:00
GUVWAF 417feee47f Fix: return failure when PhoneAPI times out (#3136)
* Add debug options for RP2040

* Rename: "observed" should be plural: "observables"

* PhoneAPI: return failure on timeout
In `onNotify()`, when disconnected, PhoneAPI removed itself from the list of observers that was looped through in `notifyObservers()`. We should exit that loop in that case.
2024-01-28 07:53:39 -06:00
Jonathan Bennett d604a76c73 Use correct define for native gos (#3133) 2024-01-26 09:06:15 -06:00
Ken McGuireandcode8buster ac9c5f81b9 Add CircutMess Chatter 2 (#3125)
* Add Chatter 2 default_envs

* Add Chatter 2 to varients

* Add Chatter 2 specific code to esp32 platform code

* Parameterize TFT_INVERT for Chatter 2 and specify setRotation to 1

* Fix formatting to make Trunk happy

* Remove commented out #define USE_LCC68

* Fix formatting again

* Add chatter2 to the CI matrix

---------

Co-authored-by: code8buster <20384924+code8buster@users.noreply.github.com>
2024-01-26 08:40:16 -06:00
Andre KandBen Meadors d6fa190025 fix: allow MQTT encryption_enabled with json_enabled (#3126)
* fix: allow MQTT `encryption_enabled` with `json_enabled`

* fix: copy decoded MeshPacket and release memory after use

* fix: use `packetPool` allocCopy and release methods

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-25 08:42:34 -06:00
Manuel f2c04c5504 fix MQTT crash (#3127) 2024-01-24 14:01:50 -06:00
Jonathan Bennett 4ae5443c3b Don't ever delete own node from DB (#3122) 2024-01-22 20:13:27 -06:00
Jonathan Bennett 6b5101ec67 Portduino logging enhancements (#3121)
* Portduino logging enhancements

* Extra debugging for SPI device
2024-01-22 01:27:06 -06:00
Jonathan Bennett 062c646814 TinyGPS fix for empty terms (#3120) 2024-01-21 19:13:54 -06:00
github-actions[bot]andthebentern bccc0d47eb [create-pull-request] automated change (#3119)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-20 19:11:21 -06:00
GUVWAFandBen Meadors 8f6a2836b8 Mark packets received via MQTT and add option to ignore them (#3117)
* Mark packets received via MQTT and add option to ignore them

* Don't send packets received via MQTT back into MQTT
Generate implicit ACK for packets we as an MQTT gateway sent

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-20 14:22:09 -06:00
github-actions[bot]andthebentern 4f76239d48 [create-pull-request] automated change (#3118)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-20 09:40:28 -06:00
rcarterazandBen Meadors 486bf79690 update default (#3114)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-19 13:41:24 -06:00
Ben Meadors 2efaaea625 Update oled dep to include RP2040 fix (#3112) 2024-01-19 13:14:27 -06:00
Manuel af157d276a fix T-Watch flip screen (#3113) 2024-01-19 13:11:19 -06:00
Ben Meadors b489ee08c8 Update radiolib 2024-01-19 10:53:00 -06:00
751bdf94aa Initial Partial Updates on t-echo (#3090)
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-19 10:28:26 -06:00
Ben Meadors e2a3b0306f Default mqtt root to msh/region from unset (#3111)
* Default mqtt root to msh/region from unset

* Correct segments
2024-01-19 07:40:14 -06:00
github-actions[bot]andthebentern a8b7490b6e [create-pull-request] automated change (#3106)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-17 18:15:00 -06:00
Andre KandBen Meadors 4056d34bed fix: ipv4_config byte order already little endian (#3073)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-17 18:14:44 -06:00
GUVWAFandBen Meadors fd8b1687a1 Update channel of node in updateUser and write to flash if needed (#3094)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-15 20:11:35 -06:00
Jonathan Bennett 8b362dee3a RadioLib 6.4.0 fixes (#3098) 2024-01-15 10:56:17 -06:00
github-actions[bot]andthebentern 30e3a28014 [create-pull-request] automated change (#3099)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-15 07:28:20 -06:00
Jonathan Bennett 14736775e2 Update define for RadioLib 6.4.0 2024-01-14 14:51:37 -06:00
Jonathan Bennett a7019b7206 Update for Radiolib 6.4.0 to fix build 2024-01-14 14:38:57 -06:00
Jonathan Bennett 6284f4ffe6 Update Linux binaries to use arch names (#3093) 2024-01-13 19:11:59 -06:00
Jonathan Bennett e4e9a1559e Drop the Raspbian and Linux targets (#3091)
* Drop the Raspbian and Linux targets

* Add lovyanGFX libdep to native
2024-01-13 16:12:26 -06:00
GUVWAF 92110276d7 Use ::printf for Portduino only 2024-01-13 14:54:43 -06:00
GUVWAF c22340eaf7 Add necessary libs to Dockerfile for native build 2024-01-13 14:54:43 -06:00
KodinLanewaveandBen Meadors 6f96fbfb74 INA3221 library branch to support negative values (#3084)
* INA3221 library branch to support negative values

Original INA3221 library does not handle negative values properly due to mishandling of signed bits in sensor reading and processing.  I have branched the library, changed the code, and tested with several deployed nodes to confirm functionality.

* Update INA3221 library reference to use version tag

Updated my library repo to reflect a version tag properly per request by meshtastic code reviewer

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-12 10:02:51 -06:00
Jonathan BennettandBen Meadors 4a867c81c0 Portduino work (#3049)
* Move to Portduino's getMacAddr()

* Add ST7735/S screen support

* Push Raspbian support into native target

* Remove latent pigpio references.

* CardKB defensive programming

* Adds configurable spidev

* Fixes to build on Fedora 40

* ENUMs are not #defines. Pull latest portduino

* Add more configuration options for SPI displays

* Add config.yaml option to set DIO3_TCXO_VOLTAGE

* change tft clear() to fillScreen()
Maintains compatability with ESPI driver.

* Adds TXen and RXen pins to portduino

* Add -c --config options to specify config file

* Fail when a specified config file is unavailable

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-12 02:00:31 -06:00
github-actions[bot]andthebentern 7e53a96ee5 [create-pull-request] automated change (#3082)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-11 12:44:46 -06:00
github-actions[bot]andthebentern 3e21e05a2c [create-pull-request] automated change (#3079)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-11 11:52:01 -06:00
Ben MeadorsandJonathan Bennett 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 MeadorsandNfN Orange 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
MictronicsandBen Meadors 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]andthebentern 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]andthebentern 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
GUVWAFandBen Meadors 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]andthebentern 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]andthebentern 2b7eb1e489 [create-pull-request] automated change (#3044)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-12-27 12:48:30 -06:00
S5NCandBen Meadors 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
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
GUVWAFandBen Meadors 2d35f72d85 SimRadio: send queue status to phone (#3041)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-27 08:16:04 -06:00
MictronicsandBen Meadors 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 NageleandBen Meadors 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 NageleandBen Meadors 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 BirssandJonathan Bennett 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]andthebentern 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 BennettandBen Meadors 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]andthebentern 17f1a450b2 [create-pull-request] automated change (#2995)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-12-06 18:14:41 -06:00
GUVWAFandBen Meadors 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]andthebentern 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]andthebentern 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
S5NCandBen Meadors 9e90b4af02 Update variant.h (#2930)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-12-02 07:46:25 -06:00
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öttgensandBen Meadors 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
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
S5NCandBen Meadors 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 f9fdb0f98d5e095b5537e9b740231368fc088210.
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
HookdomPonixandBen Meadors 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 MexicoandJonathan Bennett 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 MeadorsandJonathan Bennett 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
HookdomPonixandBen Meadors 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]andthebentern 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 MexicoandBen Meadors 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 JangandBen Meadors 45c5e0e730 cleanup disables (#2924)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-11-03 06:50:30 -05:00
github-actions[bot]andthebentern 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 634151b8ec6f4063dc95966102234ef7aba8cefd.

* 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]andthebentern 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 KandBen Meadors e6b20bff77 refactor: simplify MQTT defaults (#2893)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-10-15 18:56:47 -05:00
Andre KandBen Meadors 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
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]andthebentern 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 MeadorsandJonathan Bennett 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]andthebentern 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-ioandBen Meadors 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
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]andthebentern fbf74fc0b2 [create-pull-request] automated change (#2863)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-10-04 10:23:55 -05:00
code8busterandBen Meadors 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 BennettandBen Meadors 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
GUVWAFandBen Meadors 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
ManuelandBen Meadors 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]andthebentern 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
S5NCandBen Meadors 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
TavisandBen Meadors 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]andthebentern 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
GUVWAFandBen Meadors 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]andthebentern e96ba7cbcf [create-pull-request] automated change (#2827)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-25 06:31:22 -05:00
Andre KandBen Meadors 61f6fb22c5 move STATE_SEND_METADATA to beginning of wantConfig (#2820)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-24 07:22:54 -05:00
github-actions[bot]andthebentern db7b77c76e [create-pull-request] automated change (#2823)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-09-24 07:01:46 -05:00
Andre KandBen Meadors 350090ec0d remove residual code for mesh_sds_timeout_secs (#2821)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-09-24 06:49:35 -05:00
GUVWAFandBen Meadors cdac643749 Fix compression (#2806) (#2819)
* Fix compression: encode to bytes after `decoded` is modified

* Change payload size to decompressed length

---------

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

* Use Named Constructor to clean up code

* Move doGPSPowerSave to GPS class

* Make sure to set GPS awake on triple-click

* Cleanup and remove dead code

* Rename GPS_PIN_WAKE to GPS_PIN_STANDBY

* Actually put GPS to sleep between fixes

* add GPS_POWER_TOGGLE for heltec-tracker and t-deck

* Change GPS_THREAD_INTERVAL to 200 ms

* More dead code, compiler warnings, and add returns

* Add Number of sats to log output

* Add pgs enable and triple-click config

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

* Feed PositionModule on GPS fix

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

* Add GPS power standbyOnly option

* Delay setting time currentQuality
to avoid strange log message.

* Typos, comments, and remove unused variable

* Short-circuit the setAwake logic on GPS disable

* heltec-tracker 0.3 GPS power saving

* set en_gpio to defined state

* Fix fixed_position logic with GPS disabled

* Don't process GPS serial when not isAwake

* Add quirk for Heltec Tracker GPS powersave

---------

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

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

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

* trunk fmt

* rename vars and fix brackets

* purge invalid db entries

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

* Refactor GPS to not probe if pins not defined

* Minor cleanups related to rework

* Use Named Constructor to clean up code

* Actually disable the GPS thread

* Don't actually disable the GPS thread

* Move doGPSPowerSave to GPS class

* Make sure to set GPS awake on triple-click

---------

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

Add second i2c channel on external connector for Station G1

* Create trunk-check.yml

* Fix typo in logging

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

---------

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

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

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

* trunk fmt

* T-Watch board update

---------

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

Add second i2c channel on external connector for Station G1

* Create trunk-check.yml

---------

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

* Moving to the end of the main setup method

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

* Ambient lighting module feature

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

* Revert edits to extensions.json

* comma'd

* Update variant.h

Added the line:

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

---------

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

* Revert edits to extensions.json

* comma'd

* Update platformio.ini

Added line:

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

---------

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

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

* Limit #neighbors to what we can actually save

* Put neighbor IDs in an array

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

* Update platformio.ini

* Update variant.h

* Update platformio.ini

* Switch to our new HW_MODEL

---------

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

* remove debug code

* fix wrong logic

* fix left/right keys for cardkb

* Try to enable Q10 kb after all

* cppcheck

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

---------

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

* Send Detection Sensor Module messages on its own portnum

* Add to Ext. Notification and consolidate logic

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

* Updates

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

* Changes from feedback

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

* Fmt

* Merge conflict resolution boogered me up

* Missed a spot

* getConfiguredOrDefaultMs

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

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

* Updates

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

* Changes from feedback

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

* Fmt

* Merge conflict resolution boogered me up

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

* Updates

* Doh!

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

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

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-08-13 23:45:23 -05:00
code8buster fcfd83bc89 Remove auto GPS shutoff for fixed position nodes (#2720) 2023-08-13 15:56:49 -05:00
github-actions[bot]andthebentern a3d2b6166c [create-pull-request] automated change (#2716)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-08-12 20:49:42 -05:00
Ben Meadors 00ea6ef5ad Merge branch 'master' into raspi-portduino 2023-08-12 09:40:26 -05:00
Thomas Göttgens b5b66f43f2 Merge branch 'master' into raspi-portduino 2023-08-09 11:19:23 +02:00
Thomas Göttgens 1e71d346ae Merge branch 'master' into raspi-portduino 2023-08-03 21:36:43 +02:00
Ben Meadors 919b2d1e48 Merge branch 'master' into raspi-portduino 2023-07-31 19:00:00 -05:00
Thomas Göttgens 171cca435e Merge branch 'master' into raspi-portduino 2023-07-24 11:00:58 +02:00
Thomas Göttgens e878f55ed3 Merge branch 'master' into raspi-portduino 2023-06-27 18:13:24 +02:00
Thomas Göttgens d74cbdaa8b update platform def 2023-05-23 21:55:12 +02:00
Ben Meadors 3a5b79e4c1 Merge branch 'master' into raspi-portduino 2023-05-23 07:51:32 -05:00
Ben Meadors 9bee35118f Merge branch 'master' into raspi-portduino 2023-05-18 06:47:56 -05:00
Thomas Göttgens 80f029aa32 Merge branch 'master' into raspi-portduino 2023-05-10 17:13:32 +02:00
Thomas Göttgens b75aa79da5 Merge branch 'master' into raspi-portduino 2023-05-08 10:32:36 +02:00
Thomas Göttgens 49febc0d9d Merge branch 'master' into raspi-portduino 2023-04-24 14:58:20 +02:00
Thomas Göttgens 85818b8dfd Merge branch 'master' into raspi-portduino 2023-04-21 16:50:48 +02:00
Thomas Göttgens 7d299b06a7 Merge branch 'master' into raspi-portduino 2023-04-04 15:00:31 +02:00
Thomas Göttgens 14080d4667 Merge branch 'master' into raspi-portduino 2023-04-02 21:24:49 +02:00
Thomas Göttgens 8a806efb95 Merge branch 'master' into raspi-portduino 2023-03-27 15:30:05 +02:00
Thomas Göttgens ef2d0cb830 Merge branch 'master' into raspi-portduino 2023-03-21 09:31:49 +01:00
Ben Meadors 5e779bfb33 Merge branch 'master' into raspi-portduino 2023-03-16 14:43:23 -05:00
Thomas Göttgens 498964e04e Merge branch 'master' into raspi-portduino 2023-03-04 17:24:37 +01:00
Thomas Göttgens 7d0bea267a Merge branch 'master' into raspi-portduino 2023-02-22 10:08:20 +01:00
Thomas Göttgens ed1aa9ddb0 Merge branch 'master' into raspi-portduino 2023-02-17 12:34:00 +01:00
Thomas Göttgens 97a0b164be Merge branch 'master' into raspi-portduino 2023-02-10 00:21:47 +01:00
Ben Meadors 82706a961f Merge branch 'master' into raspi-portduino 2023-02-08 07:40:36 -06:00
Thomas Göttgens 06a1b079da even more cleanup-ing and revert-ing 2023-02-02 11:47:47 +01:00
Thomas Göttgens 56afed84df revert some more 2023-02-02 11:35:30 +01:00
Thomas Göttgens 945fd7a05c revert readprops change 2023-02-02 11:32:00 +01:00
Thomas Göttgens e9a55fc296 revert them trunk shite 2023-02-02 11:29:55 +01:00
Thomas Göttgens 472c43aace Merge remote-tracking branch 'remotes/origin/master' into raspi-portduino 2023-02-02 10:49:45 +01:00
Thomas Göttgens 8b5937892b Merge pull request #2100 from meshtastic/develop
Update Raspi branch
2023-01-04 21:11:47 +01:00
Thomas Göttgens 8c20fe5ec4 Start working on RF95 attached to Raspberry Pi 2022-12-30 21:44:51 +01:00
286 changed files with 8161 additions and 3300 deletions
+13
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:
+1 -1
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
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_aarch64
bin/config-dist.yaml
+50 -6
View File
@@ -64,8 +64,10 @@ jobs:
- board: tlora-v1 - board: tlora-v1
- board: tlora_v1_3 - board: tlora_v1_3
- board: tlora-v2-1-1_6 - board: tlora-v2-1-1_6
- board: tlora-v2-1-1_6-tcxo
- 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
@@ -78,6 +80,7 @@ jobs:
- board: m5stack-core - board: m5stack-core
- board: m5stack-coreink - board: m5stack-coreink
- board: nano-g1-explorer - board: nano-g1-explorer
- board: chatter2
uses: ./.github/workflows/build_esp32.yml uses: ./.github/workflows/build_esp32.yml
with: with:
board: ${{ matrix.board }} board: ${{ matrix.board }}
@@ -103,7 +106,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 +122,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 +214,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 +239,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_v2.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./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 +259,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 +290,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 +321,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 +381,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
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_aarch64 .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
- uses: jiro4989/build-deb-action@v3
with:
package: meshtasticd
package_root: .debpkg
maintainer: Jonathan Bennett
version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.*
arch: arm64
depends: libyaml-cpp0.7
desc: Native Linux Meshtastic binary.
- uses: actions/upload-artifact@v3
with:
name: artifact-deb
path: |
./*.deb
+22
View File
@@ -0,0 +1,22 @@
name: Pull Request
on: [pull_request]
concurrency:
group: ${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions: read-all
jobs:
trunk_check:
name: Trunk Check Runner
runs-on: ubuntu-latest
permissions:
checks: write # For trunk to post annotations
contents: read # For repo checkout
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Trunk Check
uses: trunk-io/trunk-action@v1
+1 -1
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
shims
+3
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
#
+1 -1
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:
+22 -27
View File
@@ -1,48 +1,43 @@
version: 0.1 version: 0.1
cli: cli:
version: 1.10.0 version: 1.17.2
plugins: plugins:
sources: sources:
- id: trunk - id: trunk
ref: v0.0.17 ref: v1.3.0
uri: https://github.com/trunk-io/plugins uri: https://github.com/trunk-io/plugins
lint: lint:
enabled: enabled:
- taplo@0.7.0 - bandit@1.7.5
- ruff@0.0.265 - checkov@3.1.9
- yamllint@1.32.0 - terrascan@1.18.5
- trivy@0.47.0
#- trufflehog@3.63.2-rc0
- taplo@0.8.1
- ruff@0.1.6
- isort@5.12.0 - isort@5.12.0
- markdownlint@0.34.0 - markdownlint@0.37.0
- oxipng@8.0.0 - oxipng@9.0.0
- svgo@3.0.2 - svgo@3.0.5
- actionlint@1.6.24 - actionlint@1.6.26
- flake8@6.0.0 - flake8@6.1.0
- hadolint@2.12.0 - hadolint@2.12.0
- shfmt@3.5.0 - shfmt@3.6.0
- shellcheck@0.9.0 - shellcheck@0.9.0
- black@23.3.0 - black@23.9.1
- git-diff-check - git-diff-check
- gitleaks@8.16.3 - gitleaks@8.18.1
- clang-format@14.0.0 - clang-format@16.0.3
- prettier@2.8.8 - prettier@3.1.0
disabled:
- taplo@0.7.0
- shellcheck@0.9.0
- shfmt@3.5.0
- oxipng@8.0.0
- actionlint@1.6.22
- markdownlint@0.34.0
- hadolint@2.12.0
- svgo@3.0.2
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
+5 -5
View File
@@ -12,7 +12,7 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Install build deps # Install build deps
USER root USER root
RUN apt-get update && \ RUN apt-get update && \
apt-get -y install wget python3 g++ zip python3-venv git vim ca-certificates apt-get -y install wget python3 g++ zip python3-venv git vim ca-certificates libgpiod-dev libyaml-cpp-dev libbluetooth-dev
# create a non-priveleged user & group # create a non-priveleged user & group
RUN groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh RUN groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh
@@ -27,15 +27,15 @@ 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
COPY --from=builder /tmp/firmware/release/meshtasticd_linux_amd64 /home/mesh/ COPY --from=builder /tmp/firmware/release/meshtasticd_linux_x86_64 /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_x86_64 --hwid '${HWID:-$RANDOM}'"
HEALTHCHECK NONE HEALTHCHECK NONE
+2 -2
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
+6 -3
View File
@@ -1,7 +1,7 @@
; Common settings for ESP targes, mixin with extends = esp32_base ; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base] [esp32_base]
extends = arduino_base extends = arduino_base
platform = platformio/espressif32@^6.3.2 platform = platformio/espressif32@6.3.2 # This is a temporary fix to the S3-based devices bluetooth issues until we can determine what within ESP-IDF changed and can develop a suitable patch.
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> ${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
@@ -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 =
@@ -38,8 +41,8 @@ lib_deps =
${networking_base.lib_deps} ${networking_base.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.0 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
+1 -2
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
+9 -3
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#a28dd5a9ccd5c48a9bede46037855ff83915d74b
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,14 @@ 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 lovyan03/LovyanGFX@^1.1.12
build_flags = build_flags =
${arduino_base.build_flags} ${arduino_base.build_flags}
-fPIC -fPIC
-Isrc/platform/portduino -Isrc/platform/portduino
-DRADIOLIB_EEPROM_UNSUPPORTED
-DPORTDUINO_LINUX_HARDWARE
-lbluetooth
-lgpiod
-lyaml-cpp
+4 -5
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
+2 -3
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
Binary file not shown.
Binary file not shown.
+4 -7
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,8 @@ 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 pio run --environment native
cp .pio/build/native/program $OUTDIR/meshtasticd_linux_amd64 cp .pio/build/native/program "$OUTDIR/meshtasticd_linux_$(arch)"
cp bin/device-install.* $OUTDIR cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR cp bin/device-update.* $OUTDIR
+107
View File
@@ -0,0 +1,107 @@
### 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: sx1262 # pinedio
# CS: 0
# IRQ: 10
# Busy: 11
# spidev: spidev0.1
# 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
# DIO3_TCXO_VOLTAGE: true # the Waveshare Core1262 and others are known to need this setting
# TXen: x # TX and RX enable pins
# RXen: x
### Set gpio chip to use in /dev/. Defaults to 0.
### Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
# gpiochip: 4
### Specify the SPI device to use in /dev/. Defaults to spidev0.0
### Some devices, like the pinedio, may require spidev0.1 as a workaround.
# spidev: spidev0.0
### Define GPIO buttons here:
GPIO:
# User: 6
### Define GPS
GPS:
# SerialPath: /dev/ttyS0
### Specify I2C device, or leave blank for none
I2C:
# I2CDevice: /dev/i2c-1
### 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
# Invert: true
### Waveshare 1.44inch LCD HAT
# Panel: ST7735S
# CS: 8 #Chip Select
# DC: 25 # Data/Command pin
# Backlight: 24
# Width: 128
# Height: 128
# Reset: 27
# OffsetX: 0
# OffsetY: 0
Touchscreen:
# Module: XPT2046
# CS: 7
# IRQ: 17
### Configure device for direct keyboard input
Input:
# KeyboardDevice: /dev/input/event0
###
Logging:
LogLevel: info # debug, info, warn, error
+103 -42
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
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
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
cp "release/meshtasticd_linux_$(arch)" /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
+3 -2
View File
@@ -1,7 +1,8 @@
{ {
"build": { "build": {
"arduino": { "arduino": {
"ldscript": "esp32s3_out.ld" "ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
}, },
"core": "esp32", "core": "esp32",
"extra_flags": [ "extra_flags": [
@@ -13,7 +14,7 @@
], ],
"f_cpu": "240000000L", "f_cpu": "240000000L",
"f_flash": "80000000L", "f_flash": "80000000L",
"flash_mode": "dio", "flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]], "hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3", "mcu": "esp32s3",
"variant": "t-deck" "variant": "t-deck"
+10 -5
View File
@@ -1,7 +1,8 @@
{ {
"build": { "build": {
"arduino": { "arduino": {
"ldscript": "esp32s3_out.ld" "ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
}, },
"core": "esp32", "core": "esp32",
"extra_flags": [ "extra_flags": [
@@ -14,8 +15,11 @@
], ],
"f_cpu": "240000000L", "f_cpu": "240000000L",
"f_flash": "80000000L", "f_flash": "80000000L",
"flash_mode": "dio", "flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]], "hwids": [
["0x303A", "0x1001"],
["0x303A", "0x0002"]
],
"mcu": "esp32s3", "mcu": "esp32s3",
"variant": "t-watch-s3" "variant": "t-watch-s3"
}, },
@@ -31,8 +35,9 @@
"maximum_size": 8388608, "maximum_size": 8388608,
"require_upload_port": true, "require_upload_port": true,
"use_1200bps_touch": true, "use_1200bps_touch": true,
"wait_for_upload_port": true "wait_for_upload_port": true,
"speed": 921600
}, },
"url": "http://www.lilygo.cn/", "url": "https://www.lilygo.cc/en-pl/products/t-watch-s3",
"vendor": "LilyGo" "vendor": "LilyGo"
} }
+1 -1
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"
}, },
+13 -7
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
@@ -10,10 +10,12 @@
;default_envs = heltec-v2_0 ;default_envs = heltec-v2_0
;default_envs = heltec-v2_1 ;default_envs = heltec-v2_1
;default_envs = heltec-wireless-tracker ;default_envs = heltec-wireless-tracker
;default_envs = chatter2
;default_envs = tlora-v1 ;default_envs = tlora-v1
;default_envs = tlora_v1_3 ;default_envs = tlora_v1_3
;default_envs = tlora-v2 ;default_envs = tlora-v2
;default_envs = tlora-v2-1-1_6 ;default_envs = tlora-v2-1-1_6
;default_envs = tlora-v2-1-1_6-tcxo
;default_envs = tlora-t3s3-v1 ;default_envs = tlora-t3s3-v1
;default_envs = lora-relay-v1 # nrf board ;default_envs = lora-relay-v1 # nrf board
;default_envs = t-echo ;default_envs = t-echo
@@ -26,7 +28,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
@@ -50,6 +53,7 @@ build_flags = -Wno-missing-field-initializers
-DRADIOLIB_EXCLUDE_NRF24 -DRADIOLIB_EXCLUDE_NRF24
-DRADIOLIB_EXCLUDE_RF69 -DRADIOLIB_EXCLUDE_RF69
-DRADIOLIB_EXCLUDE_SX1231 -DRADIOLIB_EXCLUDE_SX1231
-DRADIOLIB_EXCLUDE_SX1233
-DRADIOLIB_EXCLUDE_SI443X -DRADIOLIB_EXCLUDE_SI443X
-DRADIOLIB_EXCLUDE_RFM2X -DRADIOLIB_EXCLUDE_RFM2X
-DRADIOLIB_EXCLUDE_AFSK -DRADIOLIB_EXCLUDE_AFSK
@@ -67,10 +71,11 @@ build_flags = -Wno-missing-field-initializers
monitor_speed = 115200 monitor_speed = 115200
lib_deps = lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306 jgromes/RadioLib@^6.4.0
https://github.com/mathertel/OneButton#2.1.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; ESP8266_SSD1306
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#2044b2c51e91ab4cd8cc93b15e40658cd808dd06
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 +97,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 +118,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/KodinLanewave/INA3221@^1.0.0
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 +127,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
+1 -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");
+75
View File
@@ -0,0 +1,75 @@
#include "configuration.h"
#ifdef HAS_NCP5623
#include <graphics/RAKled.h>
NCP5623 rgb;
#endif
namespace concurrency
{
class AmbientLightingThread : public concurrency::OSThread
{
public:
explicit AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLightingThread")
{
// Uncomment to test module
// moduleConfig.ambient_lighting.led_state = true;
// moduleConfig.ambient_lighting.current = 10;
// // Default to a color based on our node number
// moduleConfig.ambient_lighting.red = (myNodeInfo.my_node_num & 0xFF0000) >> 16;
// moduleConfig.ambient_lighting.green = (myNodeInfo.my_node_num & 0x00FF00) >> 8;
// moduleConfig.ambient_lighting.blue = myNodeInfo.my_node_num & 0x0000FF;
#ifdef HAS_NCP5623
_type = type;
if (_type == ScanI2C::DeviceType::NONE) {
LOG_DEBUG("AmbientLightingThread disabling due to no RGB leds found on I2C bus\n");
disable();
return;
}
if (!moduleConfig.ambient_lighting.led_state) {
LOG_DEBUG("AmbientLightingThread disabling due to moduleConfig.ambient_lighting.led_state OFF\n");
disable();
return;
}
LOG_DEBUG("AmbientLightingThread initializing\n");
if (_type == ScanI2C::NCP5623) {
rgb.begin();
setLighting();
}
#endif
}
protected:
int32_t runOnce() override
{
#ifdef HAS_NCP5623
if (_type == ScanI2C::NCP5623 && moduleConfig.ambient_lighting.led_state) {
setLighting();
return 30000; // 30 seconds to reset from any animations that may have been running from Ext. Notification
} else {
return disable();
}
#else
return disable();
#endif
}
private:
ScanI2C::DeviceType _type = ScanI2C::DeviceType::NONE;
void setLighting()
{
#ifdef HAS_NCP5623
rgb.setCurrent(moduleConfig.ambient_lighting.current);
rgb.setRed(moduleConfig.ambient_lighting.red);
rgb.setGreen(moduleConfig.ambient_lighting.green);
rgb.setBlue(moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n",
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
moduleConfig.ambient_lighting.blue);
#endif
}
};
} // namespace concurrency
+77
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
+38 -10
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_PORTDUINO)
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_PORTDUINO) || defined(BUTTON_PIN)
#if defined(ARCH_PORTDUINO)
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_PORTDUINO)
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_PORTDUINO)
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_PORTDUINO)
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);
} }
@@ -164,19 +192,19 @@ class ButtonThread : public concurrency::OSThread
static void userButtonMultiPressed() static void userButtonMultiPressed()
{ {
#if defined(GPS_POWER_TOGGLE) if (!config.device.disable_triple_click && (gps != nullptr)) {
if (config.position.gps_enabled) { gps->toggleGpsMode();
LOG_DEBUG("Flag set to false for gps power\n");
} else {
LOG_DEBUG("Flag set to true to restore power\n");
} }
config.position.gps_enabled = !(config.position.gps_enabled);
doGPSpowersave(config.position.gps_enabled);
#endif
} }
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
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
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);
};
+7 -7
View File
@@ -10,12 +10,12 @@ template <class T> class Observable;
*/ */
template <class T> class Observer template <class T> class Observer
{ {
std::list<Observable<T> *> observed; std::list<Observable<T> *> observables;
public: public:
virtual ~Observer(); virtual ~Observer();
/// Stop watching the obserable /// Stop watching the observable
void unobserve(Observable<T> *o); void unobserve(Observable<T> *o);
/// Start watching a specified observable /// Start watching a specified observable
@@ -86,21 +86,21 @@ template <class T> class Observable
template <class T> Observer<T>::~Observer() template <class T> Observer<T>::~Observer()
{ {
for (typename std::list<Observable<T> *>::const_iterator iterator = observed.begin(); iterator != observed.end(); for (typename std::list<Observable<T> *>::const_iterator iterator = observables.begin(); iterator != observables.end();
++iterator) { ++iterator) {
(*iterator)->removeObserver(this); (*iterator)->removeObserver(this);
} }
observed.clear(); observables.clear();
} }
template <class T> void Observer<T>::unobserve(Observable<T> *o) template <class T> void Observer<T>::unobserve(Observable<T> *o)
{ {
o->removeObserver(this); o->removeObserver(this);
observed.remove(o); observables.remove(o);
} }
template <class T> void Observer<T>::observe(Observable<T> *o) template <class T> void Observer<T>::observe(Observable<T> *o)
{ {
observed.push_back(o); observables.push_back(o);
o->addObserver(this); o->addObserver(this);
} }
+93 -58
View File
@@ -16,8 +16,13 @@
#include "buzz/buzz.h" #include "buzz/buzz.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "meshUtils.h"
#include "sleep.h" #include "sleep.h"
#include "utils.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"
@@ -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
@@ -158,7 +164,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
#endif #endif
#ifndef BATTERY_SENSE_SAMPLES #ifndef BATTERY_SENSE_SAMPLES
#define BATTERY_SENSE_SAMPLES 30 #define BATTERY_SENSE_SAMPLES \
30 // Set the number of samples, it has an effect of increasing sensitivity in complex electromagnetic environment.
#endif #endif
#ifdef BATTERY_PIN #ifdef BATTERY_PIN
@@ -170,61 +177,75 @@ class AnalogBatteryLevel : public HasBatteryLevel
if (millis() - last_read_time_ms > min_read_interval) { if (millis() - last_read_time_ms > min_read_interval) {
last_read_time_ms = millis(); last_read_time_ms = millis();
// Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic
// environment.
uint32_t raw = 0; uint32_t raw = 0;
#ifdef ARCH_ESP32 float scaled = 0;
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) { #ifdef ARCH_ESP32 // ADC block for espressif platforms
raw += adc1_get_raw(adc_channel); raw = espAdcRead();
} scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
#else // ADC2 scaled *= operativeAdcMultiplier;
int32_t adc_buf = 0; #else // block for all other platforms
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
// ADC2 wifi bug workaround, see
// https://github.com/espressif/arduino-esp32/issues/102
WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, RTC_reg_b);
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf);
raw += adc_buf;
}
#endif // BAT_MEASURE_ADC_UNIT
#else // !ARCH_ESP32
for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) { for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += analogRead(BATTERY_PIN); raw += analogRead(BATTERY_PIN);
} }
#endif
raw = raw / BATTERY_SENSE_SAMPLES; raw = raw / BATTERY_SENSE_SAMPLES;
float scaled; scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
#ifdef ARCH_ESP32 #endif
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs); // LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
scaled *= operativeAdcMultiplier;
#else
#ifndef VBAT_RAW_TO_SCALED
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
#else
scaled = VBAT_RAW_TO_SCALED(raw); // defined in variant.h
#endif // VBAT RAW TO SCALED
#endif // ARCH_ESP32
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
last_read_value = scaled; last_read_value = scaled;
return scaled; return scaled;
} else { } else {
return last_read_value; return last_read_value;
} }
#else
return 0;
#endif // BATTERY_PIN #endif // BATTERY_PIN
return 0;
} }
#if defined(ARCH_ESP32) && !defined(HAS_PMU) && defined(BATTERY_PIN)
/**
* ESP32 specific function for getting calibrated ADC reads
*/
uint32_t espAdcRead()
{
uint32_t raw = 0;
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
#ifdef ADC_CTRL
if (heltec_version == 5) {
pinMode(ADC_CTRL, OUTPUT);
digitalWrite(ADC_CTRL, HIGH);
delay(10);
}
#endif
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += adc1_get_raw(adc_channel);
}
#ifdef ADC_CTRL
if (heltec_version == 5) {
digitalWrite(ADC_CTRL, LOW);
}
#endif
#else // ADC2
int32_t adc_buf = 0;
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
// ADC2 wifi bug workaround, see
// https://github.com/espressif/arduino-esp32/issues/102
WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, RTC_reg_b);
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf);
raw += adc_buf;
}
#endif // BAT_MEASURE_ADC_UNIT
raw = raw / BATTERY_SENSE_SAMPLES;
return raw;
}
#endif
/** /**
* return true if there is a battery installed in this unit * return true if there is a battery installed in this unit
*/ */
virtual bool isBatteryConnect() override virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
{
return getBatteryPercent() != -1;
}
/// If we see a battery voltage higher than physics allows - assume charger is pumping /// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power /// in power
@@ -245,10 +266,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
/// Assume charging if we have a battery and external power is connected. /// Assume charging if we have a battery and external power is connected.
/// we can't be smart enough to say 'full'? /// we can't be smart enough to say 'full'?
virtual bool isCharging() override virtual bool isCharging() override { return isBatteryConnect() && isVbusIn(); }
{
return isBatteryConnect() && isVbusIn();
}
private: private:
/// If we see a battery voltage higher than physics allows - assume charger is pumping /// If we see a battery voltage higher than physics allows - assume charger is pumping
@@ -275,10 +293,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;
} }
@@ -288,11 +310,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();
@@ -385,11 +408,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;
@@ -418,9 +438,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
} }
@@ -448,10 +468,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);
+7 -13
View File
@@ -8,7 +8,6 @@
* actions to be taken upon entering or exiting each state. * actions to be taken upon entering or exiting each state.
*/ */
#include "PowerFSM.h" #include "PowerFSM.h"
#include "GPS.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "configuration.h" #include "configuration.h"
@@ -46,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;
@@ -137,9 +136,6 @@ static void lsIdle()
static void lsExit() static void lsExit()
{ {
LOG_INFO("Exit state: LS\n"); LOG_INFO("Exit state: LS\n");
// setGPSPower(true); // restore GPS power
if (gps)
gps->forceWake(true);
} }
static void nbEnter() static void nbEnter()
@@ -249,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);
@@ -352,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");
@@ -365,10 +363,6 @@ void PowerFSM_setup()
getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs),
NULL, "Bluetooth timeout"); NULL, "Bluetooth timeout");
} }
if (config.power.sds_secs != UINT32_MAX)
powerFSM.add_timed_transition(lowPowerState, &stateSDS, getConfiguredOrDefaultMs(config.power.sds_secs), NULL,
"mesh timeout");
#endif #endif
powerFSM.run_machine(); // run one iteration of the state machine, so we run our on enter tasks for the initial DARK state powerFSM.run_machine(); // run one iteration of the state machine, so we run our on enter tasks for the initial DARK state
+2 -2
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;
} }
}; };
+35 -3
View File
@@ -10,6 +10,10 @@
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#ifdef ARCH_PORTDUINO
#include "platform/portduino/PortduinoGlue.h"
#endif
/** /**
* A printer that doesn't go anywhere * A printer that doesn't go anywhere
*/ */
@@ -18,6 +22,12 @@ NoopPrint noopPrint;
#if HAS_WIFI || HAS_ETHERNET #if HAS_WIFI || HAS_ETHERNET
extern Syslog syslog; extern Syslog syslog;
#endif #endif
void RedirectablePrint::rpInit()
{
#ifdef HAS_FREE_RTOS
inDebugPrint = xSemaphoreCreateMutexStatic(&this->_MutexStorageSpace);
#endif
}
void RedirectablePrint::setDestination(Print *_dest) void RedirectablePrint::setDestination(Print *_dest)
{ {
@@ -62,13 +72,24 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
{ {
if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, "DEBUG") == 0) { #ifdef ARCH_PORTDUINO
if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0)
return 0;
else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0)
return 0;
else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0)
return 0;
#endif
if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
return 0; return 0;
} }
size_t r = 0; size_t r = 0;
#ifdef HAS_FREE_RTOS
if (inDebugPrint != nullptr && xSemaphoreTake(inDebugPrint, portMAX_DELAY) == pdTRUE) {
#else
if (!inDebugPrint) { if (!inDebugPrint) {
inDebugPrint = true; inDebugPrint = true;
#endif
va_list arg; va_list arg;
va_start(arg, format); va_start(arg, format);
@@ -90,10 +111,17 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
int hour = hms / SEC_PER_HOUR; int hour = hms / SEC_PER_HOUR;
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
#ifdef ARCH_PORTDUINO
r += ::printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000);
#else
r += printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); r += printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000);
#endif
} else } else
#ifdef ARCH_PORTDUINO
r += ::printf("%s | ??:??:?? %u ", logLevel, millis() / 1000);
#else
r += printf("%s | ??:??:?? %u ", logLevel, millis() / 1000); r += printf("%s | ??:??:?? %u ", logLevel, millis() / 1000);
#endif
auto thread = concurrency::OSThread::currentThread; auto thread = concurrency::OSThread::currentThread;
if (thread) { if (thread) {
@@ -141,7 +169,11 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
va_end(arg); va_end(arg);
isContinuationMessage = !hasNewline; isContinuationMessage = !hasNewline;
#ifdef HAS_FREE_RTOS
xSemaphoreGive(inDebugPrint);
#else
inDebugPrint = false; inDebugPrint = false;
#endif
} }
return r; return r;
+8 -2
View File
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "../freertosinc.h"
#include <Print.h> #include <Print.h>
#include <stdarg.h> #include <stdarg.h>
#include <string> #include <string>
@@ -16,14 +17,19 @@ class RedirectablePrint : public Print
/// Used to allow multiple logDebug messages to appear on a single log line /// Used to allow multiple logDebug messages to appear on a single log line
bool isContinuationMessage = false; bool isContinuationMessage = false;
#ifdef HAS_FREE_RTOS
SemaphoreHandle_t inDebugPrint = nullptr;
StaticSemaphore_t _MutexStorageSpace;
#else
volatile bool inDebugPrint = false; volatile bool inDebugPrint = false;
#endif
public: public:
explicit RedirectablePrint(Print *_dest) : dest(_dest) {} explicit RedirectablePrint(Print *_dest) : dest(_dest) {}
/** /**
* Set a new destination * Set a new destination
*/ */
void rpInit();
void setDestination(Print *dest); void setDestination(Print *dest);
virtual size_t write(uint8_t c); virtual size_t write(uint8_t c);
@@ -54,4 +60,4 @@ class NoopPrint : public Print
/** /**
* A printer that doesn't go anywhere * A printer that doesn't go anywhere
*/ */
extern NoopPrint noopPrint; extern NoopPrint noopPrint;
+1
View File
@@ -12,6 +12,7 @@ SerialConsole *console;
void consoleInit() void consoleInit()
{ {
new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
DEBUG_PORT.rpInit(); // Simply sets up semaphore
} }
void consolePrintf(const char *format, ...) void consolePrintf(const char *format, ...)
+3 -2
View File
@@ -53,7 +53,7 @@ class OSThread : public Thread
static void setup(); static void setup();
int32_t disable(); virtual int32_t disable();
/** /**
* Wait a specified number msecs starting from the current time (rather than the last time we were run) * Wait a specified number msecs starting from the current time (rather than the last time we were run)
@@ -67,6 +67,7 @@ class OSThread : public Thread
* Returns desired period for next invocation (or RUN_SAME for no change) * 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();
@@ -87,4 +88,4 @@ extern bool hasBeenSetup;
void assertIsSetup(); void assertIsSetup();
} // namespace concurrency } // namespace concurrency
+11 -3
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")
@@ -101,6 +101,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// I2C Keyboards (M5Stack, RAK14004, T-Deck) // I2C Keyboards (M5Stack, RAK14004, T-Deck)
#define CARDKB_ADDR 0x5F #define CARDKB_ADDR 0x5F
#define TDECK_KB_ADDR 0x55 #define TDECK_KB_ADDR 0x55
#define BBQ10_KB_ADDR 0x1F
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// SENSOR // SENSOR
@@ -110,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
@@ -144,9 +146,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define GPS_BAUDRATE 9600 #define GPS_BAUDRATE 9600
#ifndef GPS_THREAD_INTERVAL #ifndef GPS_THREAD_INTERVAL
#define GPS_THREAD_INTERVAL 100 #define GPS_THREAD_INTERVAL 200
#endif #endif
// convert 24-bit color to 16-bit (56K)
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
/* Step #1: offer chance for variant-specific defines */ /* Step #1: offer chance for variant-specific defines */
#include "variant.h" #include "variant.h"
@@ -183,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
+2 -2
View File
@@ -30,8 +30,8 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{ {
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, RAK14004}; ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004};
return firstOfOrNONE(3, types); return firstOfOrNONE(4, types);
} }
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
+2
View File
@@ -17,6 +17,7 @@ class ScanI2C
RTC_PCF8563, RTC_PCF8563,
CARDKB, CARDKB,
TDECKKB, TDECKKB,
BBQ10KB,
RAK14004, RAK14004,
PMU_AXP192_AXP2101, PMU_AXP192_AXP2101,
BME_680, BME_680,
@@ -24,6 +25,7 @@ class ScanI2C
BMP_280, BMP_280,
INA260, INA260,
INA219, INA219,
INA3221,
MCP9808, MCP9808,
SHT31, SHT31,
SHTC3, SHTC3,
+15 -2
View File
@@ -2,7 +2,9 @@
#include "concurrency/LockGuard.h" #include "concurrency/LockGuard.h"
#include "configuration.h" #include "configuration.h"
#if defined(ARCH_PORTDUINO)
#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);
@@ -213,6 +222,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
break; break;
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n"); SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found\n");
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n"); SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
#ifdef HAS_NCP5623 #ifdef HAS_NCP5623
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n"); SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
@@ -250,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) {
+2 -2
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;
}; };
+840 -555
View File
File diff suppressed because it is too large Load Diff
+137 -74
View File
@@ -2,7 +2,16 @@
#include "GPSStatus.h" #include "GPSStatus.h"
#include "Observer.h" #include "Observer.h"
#include "TinyGPS++.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
#include "input/RotaryEncoderInterruptImpl1.h"
#include "input/UpDownInterruptImpl1.h"
#include "modules/PositionModule.h"
// Allow defining the polarity of the ENABLE output. default is active high
#ifndef GPS_EN_ACTIVE
#define GPS_EN_ACTIVE 1
#endif
struct uBloxGnssModelInfo { struct uBloxGnssModelInfo {
char swVersion[30]; char swVersion[30];
@@ -14,10 +23,17 @@ 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;
typedef enum {
GNSS_RESPONSE_NONE,
GNSS_RESPONSE_NAK,
GNSS_RESPONSE_FRAME_ERRORS,
GNSS_RESPONSE_OK,
} GPS_RESPONSE;
// Generate a string representation of DOP // Generate a string representation of DOP
const char *getDOPString(uint32_t dop); const char *getDOPString(uint32_t dop);
@@ -28,26 +44,49 @@ const char *getDOPString(uint32_t dop);
*/ */
class GPS : private concurrency::OSThread class GPS : private concurrency::OSThread
{ {
TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA
uint32_t lastChecksumFailCount = 0;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
// via optional feature "custom fields", currently disabled (bug #525)
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
uint8_t fixType = 0; // fix type from GPGSA
#endif
private: private:
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastWhileActiveMsec = 0; uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0;
const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600};
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;
uint32_t en_gpio = 0;
int32_t averageLockTime = 0;
uint32_t GPSCycles = 0;
int speedSelect = 0;
int probeTries = 2;
/** /**
* hasValidLocation - indicates that the position variables contain a complete * 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
bool isAwake = false; // true if we want a location right now bool isAwake = false; // true if we want a location right now
bool wakeAllowed = true; // false if gps must be forced to sleep regardless of what time it is bool isInPowersave = false;
bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop() bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop()
bool hasGPS = false; // Do we have a GPS we are talking to bool hasGPS = false; // Do we have a GPS we are talking to
bool GPSInitFinished = false; // Init thread finished?
bool GPSInitStarted = false; // Init thread finished?
uint8_t numSatellites = 0; uint8_t numSatellites = 0;
CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep);
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep); CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
CallbackObserver<GPS, void *> notifyGPSSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep); CallbackObserver<GPS, void *> notifyGPSSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
@@ -55,6 +94,25 @@ 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 uint8_t _message_PMREQ[];
static const uint8_t _message_CFG_RXM_PSM[];
static const uint8_t _message_CFG_RXM_ECO[];
static const uint8_t _message_CFG_PM2[];
static const uint8_t _message_GNSS_7[];
static const uint8_t _message_GNSS[];
static const uint8_t _message_JAM[];
static const uint8_t _message_NAVX5[];
static const uint8_t _message_1HZ[];
static const uint8_t _message_GLL[];
static const uint8_t _message_GSA[];
static const uint8_t _message_GSV[];
static const uint8_t _message_VTG[];
static const uint8_t _message_RMC[];
static const uint8_t _message_AID[];
static const uint8_t _message_GGA[];
static const uint8_t _message_PMS[];
static const uint8_t _message_SAVE[];
meshtastic_Position p = meshtastic_Position_init_default; meshtastic_Position p = meshtastic_Position_init_default;
GPS() : concurrency::OSThread("GPS") {} GPS() : concurrency::OSThread("GPS") {}
@@ -69,6 +127,17 @@ class GPS : private concurrency::OSThread
*/ */
virtual bool setup(); virtual bool setup();
// re-enable the thread
void enable();
// Disable the thread
int32_t disable() override;
// toggle between enabled/disabled
void toggleGpsMode();
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();
@@ -78,73 +147,22 @@ class GPS : private concurrency::OSThread
/// Return true if we are connected to a GPS /// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; } bool isConnected() const { return hasGPS; }
bool isPowerSaving() const { return !config.position.gps_enabled; } bool isPowerSaving() const { return config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED; }
/**
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP
* called after the CPU wakes from light-sleep state
*
* Or set to false, to disallow any sort of waking
* */
void forceWake(bool on);
// Some GPS modules (ublock) require factory reset
virtual bool factoryReset() { return true; }
// Empty the input buffer as quickly as possible // Empty the input buffer as quickly as possible
void clearBuffer(); void clearBuffer();
protected: // Create a ublox packet for editing in memory
/// Do gps chipset specific init, return true for success uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
virtual bool setupGPS();
/// If possible force the GPS into sleep/low power mode // scratch space for creating ublox packets
virtual void sleep(); uint8_t UBXscratch[250] = {0};
/// wake the GPS into normal operation mode int rebootsSeen = 0;
virtual void wake();
/** Subclasses should look for serial rx characters here and feed it to their GPS parser 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);
* Return true if we received a valid message from the GPS GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
*/
virtual bool whileIdle() = 0;
/** Idle processing while GPS is looking for lock, called once per secondish */
virtual void whileActive() {}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime() = 0;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation() = 0;
/// Record that we have a GPS
void setConnected();
void setNumSatellites(uint8_t n);
private:
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareSleep(void *unused);
/// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareDeepSleep(void *unused);
// Calculate checksum
void UBXChecksum(byte *message, size_t length);
/** /**
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
@@ -152,6 +170,59 @@ class GPS : private concurrency::OSThread
* calls sleep/wake * calls sleep/wake
*/ */
void setAwake(bool on); void setAwake(bool on);
virtual bool factoryReset();
// Creates an instance of the GPS class.
// Returns the new instance or null if the GPS is not present.
static GPS *createGps();
protected:
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
/// Record that we have a GPS
void setConnected();
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation();
private:
/// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareDeepSleep(void *unused);
// Calculate checksum
void UBXChecksum(uint8_t *message, size_t length);
/** Get how long we should stay looking for each aquisition /** Get how long we should stay looking for each aquisition
*/ */
@@ -161,8 +232,6 @@ class GPS : private concurrency::OSThread
*/ */
uint32_t getSleepTime() const; uint32_t getSleepTime() const;
bool getACK(uint8_t c, uint8_t i);
/** /**
* Tell users we have new GPS readings * Tell users we have new GPS readings
*/ */
@@ -172,9 +241,7 @@ class GPS : private concurrency::OSThread
// Get GNSS model // Get GNSS model
String getNMEA(); String getNMEA();
GnssModel_t probe(); GnssModel_t probe(int serialSpeed);
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
// delay counter to allow more sats before fixed position stops GPS thread // delay counter to allow more sats before fixed position stops GPS thread
uint8_t fixeddelayCtr = 0; uint8_t fixeddelayCtr = 0;
@@ -183,8 +250,4 @@ class GPS : private concurrency::OSThread
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN; GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
}; };
// Creates an instance of the GPS class.
// Returns the new instance or null if the GPS is not present.
GPS *createGps();
extern GPS *gps; extern GPS *gps;
-272
View File
@@ -1,272 +0,0 @@
#include "NMEAGPS.h"
#include "RTC.h"
#include "configuration.h"
#include <TinyGPS++.h>
// GPS solutions older than this will be rejected - see TinyGPSDatum::age()
#define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway
#define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc)
static int32_t toDegInt(RawDegrees d)
{
int32_t degMult = 10000000; // 1e7
int32_t r = d.deg * degMult + d.billionths / 100;
if (d.negative)
r *= -1;
return r;
}
bool NMEAGPS::factoryReset()
{
#ifdef PIN_GPS_REINIT
// The L76K GNSS on the T-Echo requires the RESET pin to be pulled LOW
digitalWrite(PIN_GPS_REINIT, 0);
pinMode(PIN_GPS_REINIT, OUTPUT);
delay(150); // The L76K datasheet calls for at least 100MS delay
digitalWrite(PIN_GPS_REINIT, 1);
#endif
// send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX.
// Factory Reset
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
_serial_gps->write(_message_reset, sizeof(_message_reset));
delay(1000);
return true;
}
bool NMEAGPS::setupGPS()
{
GPS::setupGPS();
#ifdef PIN_GPS_PPS
// pulse per second
// FIXME - move into shared GPS code
pinMode(PIN_GPS_PPS, INPUT);
#endif
// Currently disabled per issue #525 (TinyGPS++ crash bug)
// when fixed upstream, can be un-disabled to enable 3D FixType and PDOP
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// see NMEAGPS.h
gsafixtype.begin(reader, NMEA_MSG_GXGSA, 2);
gsapdop.begin(reader, NMEA_MSG_GXGSA, 15);
LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n");
#else
LOG_DEBUG("GxGSA NOT available\n");
#endif
return true;
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool NMEAGPS::lookForTime()
{
auto ti = reader.time;
auto d = reader.date;
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
/* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
struct tm t;
t.tm_sec = ti.second();
t.tm_min = ti.minute();
t.tm_hour = ti.hour();
t.tm_mday = d.day();
t.tm_mon = d.month() - 1;
t.tm_year = d.year() - 1900;
t.tm_isdst = false;
if (t.tm_mon > -1) {
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t);
return true;
} else
return false;
} else
return false;
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool NMEAGPS::lookForLocation()
{
// By default, TinyGPS++ does not parse GPGSA lines, which give us
// the 2D/3D fixType (see NMEAGPS.h)
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
fixQual = reader.fixQuality();
#ifndef TINYGPS_OPTION_NO_STATISTICS
if (reader.failedChecksum() > lastChecksumFailCount) {
LOG_WARN("Warning, %u new GPS checksum failures, for a total of %u.\n", reader.failedChecksum() - lastChecksumFailCount,
reader.failedChecksum());
lastChecksumFailCount = reader.failedChecksum();
}
#endif
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
fixType = atoi(gsafixtype.value()); // will set to zero if no data
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
#endif
// check if GPS has an acceptable lock
if (!hasLock())
return false;
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n", reader.location.age(),
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
gsafixtype.age(),
#else
0,
#endif
reader.date.age(), reader.time.age());
#endif // GPS_EXTRAVERBOSE
// check if a complete GPS solution set is available for reading
// tinyGPSDatum::age() also includes isValid() test
// FIXME
if (!((reader.location.age() < GPS_SOL_EXPIRY_MS) &&
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
(gsafixtype.age() < GPS_SOL_EXPIRY_MS) &&
#endif
(reader.time.age() < GPS_SOL_EXPIRY_MS) && (reader.date.age() < GPS_SOL_EXPIRY_MS))) {
LOG_WARN("SOME data is TOO OLD: LOC %u, TIME %u, DATE %u\n", reader.location.age(), reader.time.age(), reader.date.age());
return false;
}
// Is this a new point or are we re-reading the previous one?
if (!reader.location.isUpdated())
return false;
// We know the solution is fresh and valid, so just read the data
auto loc = reader.location.value();
// Bail out EARLY to avoid overwriting previous good data (like #857)
if (toDegInt(loc.lat) > 900000000) {
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("Bail out EARLY on LAT %i\n", toDegInt(loc.lat));
#endif
return false;
}
if (toDegInt(loc.lng) > 1800000000) {
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("Bail out EARLY on LNG %i\n", toDegInt(loc.lng));
#endif
return false;
}
p.location_source = meshtastic_Position_LocSource_LOC_INTERNAL;
// Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
p.HDOP = reader.hdop.value();
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
// LOG_DEBUG("PDOP=%d, HDOP=%d\n", p.PDOP, p.HDOP);
#else
// FIXME! naive PDOP emulation (assumes VDOP==HDOP)
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)
p.HDOP = reader.hdop.value();
p.PDOP = 1.41 * reader.hdop.value();
#endif
// Discard incomplete or erroneous readings
if (reader.hdop.value() == 0) {
LOG_WARN("BOGUS hdop.value() REJECTED: %d\n", reader.hdop.value());
return false;
}
p.latitude_i = toDegInt(loc.lat);
p.longitude_i = toDegInt(loc.lng);
p.altitude_geoidal_separation = reader.geoidHeight.meters();
p.altitude_hae = reader.altitude.meters() + p.altitude_geoidal_separation;
p.altitude = reader.altitude.meters();
p.fix_quality = fixQual;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
p.fix_type = fixType;
#endif
// positional timestamp
struct tm t;
t.tm_sec = reader.time.second();
t.tm_min = reader.time.minute();
t.tm_hour = reader.time.hour();
t.tm_mday = reader.date.day();
t.tm_mon = reader.date.month() - 1;
t.tm_year = reader.date.year() - 1900;
t.tm_isdst = false;
p.timestamp = mktime(&t);
// Nice to have, if available
if (reader.satellites.isUpdated()) {
p.sats_in_view = reader.satellites.value();
}
if (reader.course.isUpdated() && reader.course.isValid()) {
if (reader.course.value() < 36000) { // sanity check
p.ground_track =
reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
} else {
LOG_WARN("BOGUS course.value() REJECTED: %d\n", reader.course.value());
}
}
if (reader.speed.isUpdated() && reader.speed.isValid()) {
p.ground_speed = reader.speed.kmph();
}
return true;
}
bool NMEAGPS::hasLock()
{
// Using GPGGA fix quality indicator
if (fixQual >= 1 && fixQual <= 5) {
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// Use GPGSA fix type 2D/3D (better) if available
if (fixType == 3 || fixType == 0) // zero means "no data received"
#endif
return true;
}
return false;
}
bool NMEAGPS::hasFlow()
{
return reader.passedChecksum() > 0;
}
bool NMEAGPS::whileIdle()
{
bool isValid = false;
#ifdef SERIAL_BUFFER_SIZE
if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) {
LOG_WARN("GPS Buffer full with %u bytes waiting. Flushing to avoid corruption.\n", _serial_gps->available());
clearBuffer();
}
#endif
// if (_serial_gps->available() > 0)
// LOG_DEBUG("GPS Bytes Waiting: %u\n", _serial_gps->available());
// First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) {
int c = _serial_gps->read();
// LOG_DEBUG("%c", c);
isValid |= reader.encode(c);
}
return isValid;
}
-57
View File
@@ -1,57 +0,0 @@
#pragma once
#include "GPS.h"
#include "Observer.h"
#include "TinyGPS++.h"
/**
* A gps class thatreads from a NMEA GPS stream (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class NMEAGPS : public GPS
{
TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA
uint32_t lastChecksumFailCount = 0;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
// via optional feature "custom fields", currently disabled (bug #525)
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
uint8_t fixType = 0; // fix type from GPGSA
#endif
public:
virtual bool setupGPS() override;
virtual bool factoryReset() override;
protected:
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime() override;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation() override;
virtual bool hasLock() override;
virtual bool hasFlow() override;
};
+3 -4
View File
@@ -103,9 +103,8 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
bool shouldSet; bool shouldSet;
if (q > currentQuality) { if (q > currentQuality) {
currentQuality = q;
shouldSet = true; shouldSet = true;
LOG_DEBUG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q); LOG_DEBUG("Upgrading time to quality %d\n", q);
} else if (q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) { } else if (q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift // Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
shouldSet = true; shouldSet = true;
@@ -114,12 +113,12 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
shouldSet = false; shouldSet = false;
if (shouldSet) { if (shouldSet) {
currentQuality = q;
lastSetMsec = now; lastSetMsec = now;
// This delta value works on all platforms // This delta value works on all platforms
timeStartMsec = now; timeStartMsec = now;
zeroOffsetSecs = tv->tv_sec; zeroOffsetSecs = tv->tv_sec;
// If this platform has a setable RTC, set it // If this platform has a setable RTC, set it
#ifdef RV3028_RTC #ifdef RV3028_RTC
if (rtc_found.address == RV3028_RTC) { if (rtc_found.address == RV3028_RTC) {
@@ -153,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
+238
View File
@@ -0,0 +1,238 @@
uint8_t GPS::_message_PMREQ[] PROGMEM = {
0x00, 0x00, // 4 bytes duration of request task
0x00, 0x00, // (milliseconds)
0x02, 0x00, // Task flag bitfield
0x00, 0x00 // byte index 1 = sleep mode
};
const uint8_t GPS::_message_CFG_RXM_PSM[] PROGMEM = {
0x08, // Reserved
0x01 // Power save mode
};
// only for Neo-6
const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = {
0x08, // Reserved
0x04 // eco mode
};
const uint8_t GPS::_message_CFG_PM2[] PROGMEM = {
0x01, // version
0x00, // Reserved 1, set to 0x06 by u-Center
0x00, // Reserved 2
0x00, // Reserved 1
0x00, 0x11, 0x03, 0x00, // flags-> cyclic mode, wait for normal fix ok, do not wake to update RTC or EPH, doNotEnterOff,
// LimitPeakCurrent
0xE8, 0x03, 0x00, 0x00, // update period 1000 ms
0x10, 0x27, 0x00, 0x00, // search period 10s
0x00, 0x00, 0x00, 0x00, // Grid offset 0
0x01, 0x00, // onTime 1 second
0x00, 0x00, // min search time 0
0x00, 0x00, // 0x2C, 0x01, // reserved 4
0x00, 0x00, // 0x00, 0x00, // reserved 5
0x00, 0x00, 0x00, 0x00, // 0x4F, 0xC1, 0x03, 0x00, // reserved 6
0x00, 0x00, 0x00, 0x00, // 0x87, 0x02, 0x00, 0x00, // reserved 7
0x00, // 0xFF, // reserved 8
0x00, // 0x00, // reserved 9
0x00, 0x00, // 0x00, 0x00, // reserved 10
0x00, 0x00, 0x00, 0x00 // 0x64, 0x40, 0x01, 0x00 // reserved 11
};
const uint8_t GPS::_message_GNSS_7[] = {
0x00, // msgVer (0 for this version)
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
0x02, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x00, 0x01, // GPS
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x01 // SBAS
};
// It's not critical if the module doesn't acknowledge this configuration.
// The module should operate adequately with its factory or previously saved settings.
// It appears that there is a firmware bug in some GPS modules: When an attempt is made
// to overwrite a saved state with identical values, no ACK/NAK is received, contrary to
// what is specified in the Ublox documentation.
// There is also a possibility that the module may be GPS-only.
const uint8_t GPS::_message_GNSS[] = {
0x00, // msgVer (0 for this version)
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
0x03, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, // GPS
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, // SBAS
0x06, 0x08, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x01 // GLONASS
};
// Enable jamming/interference monitor
// For Neo-6
const uint8_t GPS::_message_JAM[] = {
0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable = 1, reserved bits 0x16B156
0x1e, 0x03, 0x00, 0x00 // config2 antennaSetting Unknown = 0, reserved 3, = 0x00,0x00, reserved 2 = 0x31E
};
/* // WIP GPS reconfig
// For Neo-6, Max-7 and Neo-7
const uint8_t GPS::_message_JAM_6_7[] = {
0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable = 1, reserved bits 0x16B156
0x1e, 0x03, 0x00, 0x00 // config2 antennaSetting Unknown = 0, reserved 3, = 0x00,0x00, reserved 2 = 0x31E
};
// For M8
const uint8_t GPS::_message_JAM_8[] = {
0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable1 = 1, reserved bits 0x16B156
0x1e, 0x43, 0x00, 0x00 // config2 antennaSetting Unknown = 0, enable2 = 1, generalBits = 0x31E
};
*/
// Configure navigation engine expert settings:
// there are many variations of what were Reserved fields for the Neo-6 in later versions
// ToDo: check UBX-MON-VER for module type and protocol version
// For the Neo-6
const uint8_t GPS::_message_NAVX5[] = {
0x00, 0x00, // msgVer (0 for this version)
0x4c, 0x66, // mask1
0x00, 0x00, 0x00, 0x00, // Reserved 0
0x00, // Reserved 1
0x00, // Reserved 2
0x03, // minSVs (Minimum number of satellites for navigation) = 3
0x10, // maxSVs (Maximum number of satellites for navigation) = 16
0x06, // minCNO (Minimum satellite signal level for navigation) = 6 dBHz
0x00, // Reserved 5
0x00, // iniFix3D (Initial fix must be 3D) (0 = false 1 = true)
0x00, // Reserved 6
0x00, // Reserved 7
0x00, // Reserved 8
0x00, 0x00, // wknRollover 0 = firmware default
0x00, 0x00, 0x00, 0x00, // Reserved 9
0x00, // Reserved 10
0x00, // Reserved 11
0x00, // usePPP (Precice Point Positioning) (0 = false, 1 = true)
0x01, // useAOP (AssistNow Autonomous configuration) = 1 (enabled)
0x00, // Reserved 12
0x00, // Reserved 13
0x00, 0x00, // aopOrbMaxErr = 0 to reset to firmware default
0x00, // Reserved 14
0x00, // Reserved 15
0x00, 0x00, // Reserved 3
0x00, 0x00, 0x00, 0x00 // Reserved 4
};
// Set GPS update rate to 1Hz
// Lowering the update rate helps to save power.
// Additionally, for some new modules like the M9/M10, an update rate lower than 5Hz
// is recommended to avoid a known issue with satellites disappearing.
const uint8_t GPS::_message_1HZ[] = {
0xE8, 0x03, // Measurement Rate (1000ms for 1Hz)
0x01, 0x00, // Navigation rate, always 1 in GPS mode
0x01, 0x00 // Time reference
};
// Disable GLL. GLL - Geographic position (latitude and longitude), which provides the current geographical
// coordinates.
const uint8_t GPS::_message_GLL[] = {
0xF0, 0x01, // NMEA ID for GLL
0x00, // Rate for DDC
0x00, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
// the DOP (Dilution of Precision)
const uint8_t GPS::_message_GSA[] = {
0xF0, 0x02, // NMEA ID for GSA
0x00, // Rate for DDC
0x01, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Disable GSV. GSV - Satellites in view, details the number and location of satellites in view.
const uint8_t GPS::_message_GSV[] = {
0xF0, 0x03, // NMEA ID for GSV
0x00, // Rate for DDC
0x00, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to
// the ground.
const uint8_t GPS::_message_VTG[] = {
0xF0, 0x05, // NMEA ID for VTG
0x00, // Rate for DDC
0x00, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data.
const uint8_t GPS::_message_RMC[] = {
0xF0, 0x04, // NMEA ID for RMC
0x00, // Rate for DDC
0x01, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data.
const uint8_t GPS::_message_GGA[] = {
0xF0, 0x00, // NMEA ID for GGA
0x00, // Rate for DDC
0x01, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Disable UBX-AID-ALPSRV as it may confuse TinyGPS. The Neo-6 seems to send this message
// whether the AID Autonomous is enabled or not
const uint8_t GPS::_message_AID[] = {
0x0B, 0x32, // NMEA ID for UBX-AID-ALPSRV
0x00, // Rate for DDC
0x00, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// The Power Management configuration allows the GPS module to operate in different power modes for optimized
// power consumption. The modes supported are: 0x00 = Full power: The module operates at full power with no power
// saving. 0x01 = Balanced: The module dynamically adjusts the tracking behavior to balance power consumption.
// 0x02 = Interval: The module operates in a periodic mode, cycling between tracking and power saving states.
// 0x03 = Aggressive with 1 Hz: The module operates in a power saving mode with a 1 Hz update rate.
// 0x04 = Aggressive with 2 Hz: The module operates in a power saving mode with a 2 Hz update rate.
// 0x05 = Aggressive with 4 Hz: The module operates in a power saving mode with a 4 Hz update rate.
// The 'period' field specifies the position update and search period. It is only valid when the powerSetupValue
// is set to Interval; otherwise, it must be set to '0'. The 'onTime' field specifies the duration of the ON phase
// and must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise,
// it must be set to '0'.
// This command applies to M8 and higher products
const uint8_t GPS::_message_PMS[] = {
0x00, // Version (0)
0x03, // Power setup value 3 = Agresssive 1Hz
0x00, 0x00, // period: not applicable, set to 0
0x00, 0x00, // onTime: not applicable, set to 0
0x00, 0x00 // reserved, generated by u-center
};
const uint8_t GPS::_message_SAVE[] = {
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x17 // deviceMask: BBR, Flash, EEPROM, and SPI Flash
};
+22 -19
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;
@@ -55,7 +55,7 @@ GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus) EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{ {
#if defined(TTGO_T_ECHO) #if defined(TTGO_T_ECHO)
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT); setGeometry(GEOMETRY_RAWMODE, 200, 200);
#elif defined(RAK4630) #elif defined(RAK4630)
// GxEPD2_213_BN - RAK14000 2.13 inch b/w 250x122 // GxEPD2_213_BN - RAK14000 2.13 inch b/w 250x122
@@ -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));
@@ -130,8 +129,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
LOG_DEBUG("Updating E-Paper... "); LOG_DEBUG("Updating E-Paper... ");
#if defined(TTGO_T_ECHO) #if defined(TTGO_T_ECHO)
// ePaper.Reset(); // wake the screen from sleep adafruitDisplay->nextPage();
adafruitDisplay->display(false); // FIXME, use partial update mode
#elif defined(RAK4630) || defined(MAKERPYTHON) #elif defined(RAK4630) || defined(MAKERPYTHON)
// RAK14000 2.13 inch b/w 250x122 actually now does support partial updates // RAK14000 2.13 inch b/w 250x122 actually now does support partial updates
@@ -148,7 +146,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 +192,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)
@@ -210,6 +209,7 @@ bool EInkDisplay::connect()
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel); adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
adafruitDisplay->init(); adafruitDisplay->init();
adafruitDisplay->setRotation(3); adafruitDisplay->setRotation(3);
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
} }
#elif defined(RAK4630) || defined(MAKERPYTHON) #elif defined(RAK4630) || defined(MAKERPYTHON)
{ {
@@ -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)
{ {
@@ -271,4 +274,4 @@ bool EInkDisplay::connect()
return true; return true;
} }
#endif #endif
-2
View File
@@ -1,5 +1,3 @@
#include "main.h"
#ifdef HAS_NCP5623 #ifdef HAS_NCP5623
#include <NCP5623.h> #include <NCP5623.h>
extern NCP5623 rgb; extern NCP5623 rgb;
+190 -247
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"
@@ -36,18 +37,25 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include "mesh/Channels.h" #include "mesh/Channels.h"
#include "mesh/generated/meshtastic/deviceonly.pb.h" #include "mesh/generated/meshtastic/deviceonly.pb.h"
#include "meshUtils.h"
#include "modules/ExternalNotificationModule.h" #include "modules/ExternalNotificationModule.h"
#include "modules/TextMessageModule.h" #include "modules/TextMessageModule.h"
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
#include "utils.h"
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
#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_PORTDUINO
#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);
@@ -365,7 +371,7 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled // Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet) static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
{ {
return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled; return packet->from != 0 && !moduleConfig.store_forward.enabled;
} }
/// Draw the last text message we received /// Draw the last text message we received
@@ -552,15 +558,20 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
} }
} }
// Draw status when gps is disabled by PMU // Draw status when GPS is disabled or not present
static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{ {
String displayLine = "GPS disabled"; String displayLine;
int16_t xPos = display->getStringWidth(displayLine); int pos;
if (y < FONT_HEIGHT_SMALL) { // Line 1: use short string
if (!config.position.gps_enabled) { displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "No GPS" : "GPS off";
display->drawString(x + xPos, y, displayLine); pos = SCREEN_WIDTH - display->getStringWidth(displayLine);
} else {
displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "GPS not present"
: "GPS is disabled";
pos = (SCREEN_WIDTH - display->getStringWidth(displayLine)) / 2;
} }
display->drawString(x + pos, y, displayLine);
} }
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
@@ -588,7 +599,7 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
String displayLine = ""; String displayLine = "";
if (!gps->getIsConnected() && !config.position.fixed_position) { if (!gps->getIsConnected() && !config.position.fixed_position) {
displayLine = "No GPS Module"; displayLine = "No GPS present";
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine); display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} else if (!gps->getHasLock() && !config.position.fixed_position) { } else if (!gps->getHasLock() && !config.position.fixed_position) {
displayLine = "No GPS Lock"; displayLine = "No GPS Lock";
@@ -906,28 +917,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_PORTDUINO
if (settingsMap[displayPanel] != no_screen) {
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 +964,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 +981,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_PORTDUINO
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 +1007,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 +1041,27 @@ 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(); #if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014)
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
#else
dispdev->flipScreenVertically();
#endif
} }
#endif #endif
@@ -1035,20 +1069,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_PORTDUINO
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_PORTDUINO
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 +1113,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 +1144,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 +1220,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 +1245,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 +1277,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 +1288,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 +1353,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_PORTDUINO)
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 +1362,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 +1376,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 +1393,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 +1406,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 +1418,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 +1464,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 +1482,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 +1493,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 +1509,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;
} }
@@ -1512,7 +1554,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus); drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus);
} }
// Display GPS status // Display GPS status
if (!config.position.gps_enabled) { if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
drawGPSpowerstat(display, x, y + 2, gpsStatus); drawGPSpowerstat(display, x, y + 2, gpsStatus);
} else { } else {
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
@@ -1554,7 +1596,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_PORTDUINO) && \
!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 +1624,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_PORTDUINO)
const char *wifiName = config.network.wifi_ssid; const char *wifiName = config.network.wifi_ssid;
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
@@ -1635,69 +1678,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 +1736,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)
@@ -1819,7 +1782,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
char chUtil[13]; char chUtil[13];
snprintf(chUtil, sizeof(chUtil), "ChUtil %2.0f%%", airTime->channelUtilizationPercent()); snprintf(chUtil, sizeof(chUtil), "ChUtil %2.0f%%", airTime->channelUtilizationPercent());
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
if (config.position.gps_enabled) { if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
// Line 3 // Line 3
if (config.display.gps_format != if (config.display.gps_format !=
meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
@@ -1828,10 +1791,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// Line 4 // Line 4
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus); drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
} else { } else {
drawGPSpowerstat(display, x - (SCREEN_WIDTH / 4), y + FONT_HEIGHT_SMALL * 2, gpsStatus); drawGPSpowerstat(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
#ifdef GPS_POWER_TOGGLE
display->drawString(x + 30, (y + FONT_HEIGHT_SMALL * 3), " by button");
#endif
} }
/* Display a heartbeat pixel that blinks every time the frame is redrawn */ /* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
@@ -1840,23 +1800,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 +1834,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);
} }
} }
+7 -16
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
+199 -35
View File
@@ -1,12 +1,16 @@
#include "configuration.h" #include "configuration.h"
#include "main.h"
#if ARCH_PORTDUINO
#include "platform/portduino/PortduinoGlue.h"
#endif
#ifndef TFT_BACKLIGHT_ON #ifndef TFT_BACKLIGHT_ON
#define TFT_BACKLIGHT_ON HIGH #define TFT_BACKLIGHT_ON HIGH
#endif #endif
// convert 24-bit color to 16-bit (56K) #ifndef TFT_MESH
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94) #define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
#endif
#if defined(ST7735S) #if defined(ST7735S)
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip #include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
@@ -15,6 +19,10 @@
#define TFT_BL ST7735_BACKLIGHT_EN #define TFT_BL ST7735_BACKLIGHT_EN
#endif #endif
#ifndef TFT_INVERT
#define TFT_INVERT true
#endif
class LGFX : public lgfx::LGFX_Device class LGFX : public lgfx::LGFX_Device
{ {
lgfx::Panel_ST7735S _panel_instance; lgfx::Panel_ST7735S _panel_instance;
@@ -64,7 +72,7 @@ class LGFX : public lgfx::LGFX_Device
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout cfg.dummy_read_pixel = 8; // 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.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.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.invert = TFT_INVERT; // 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.rgb_order = false; // Set to true if the panel's red and blue are swapped
cfg.dlen_16bit = cfg.dlen_16bit =
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
@@ -81,8 +89,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 +110,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 +240,7 @@ class LGFX : public lgfx::LGFX_Device
} }
}; };
static LGFX tft; static LGFX *tft = nullptr;
#elif defined(ILI9341_DRIVER) #elif defined(ILI9341_DRIVER)
@@ -309,23 +329,95 @@ 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_PORTDUINO
#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)
{
if (settingsMap[displayPanel] == st7789)
_panel_instance = new lgfx::Panel_ST7789;
else if (settingsMap[displayPanel] == st7735)
_panel_instance = new lgfx::Panel_ST7735;
else if (settingsMap[displayPanel] == st7735s)
_panel_instance = new lgfx::Panel_ST7735S;
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.pin_rst = settingsMap[displayReset];
cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
cfg.offset_x = settingsMap[displayOffsetX]; // Panel offset amount in X direction
cfg.offset_y = settingsMap[displayOffsetY]; // Panel offset amount in Y direction
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
cfg.invert = settingsMap[displayInvert]; // Set to true if the light/darkness of the panel is reversed
_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_PORTDUINO
#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_PORTDUINO
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 +425,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 +463,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_PORTDUINO
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_PORTDUINO
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 +536,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 +552,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 +570,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) || defined(CHATTER_2)
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;
} }
+2 -1
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();
+2 -2
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_PORTDUINO) && \
!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"
+181
View File
@@ -0,0 +1,181 @@
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
#include <Arduino.h>
#include "BBQ10Keyboard.h"
#define _REG_VER 1
#define _REG_CFG 2
#define _REG_INT 3
#define _REG_KEY 4
#define _REG_BKL 5
#define _REG_DEB 6
#define _REG_FRQ 7
#define _REG_RST 8
#define _REG_FIF 9
#define _WRITE_MASK (1 << 7)
#define CFG_OVERFLOW_ON (1 << 0)
#define CFG_OVERFLOW_INT (1 << 1)
#define CFG_CAPSLOCK_INT (1 << 2)
#define CFG_NUMLOCK_INT (1 << 3)
#define CFG_KEY_INT (1 << 4)
#define CFG_PANIC_INT (1 << 5)
#define CFG_REPORT_MODS (1 << 6)
#define CFG_USE_MODS (1 << 7)
#define INT_OVERFLOW (1 << 0)
#define INT_CAPSLOCK (1 << 1)
#define INT_NUMLOCK (1 << 2)
#define INT_KEY (1 << 3)
#define INT_PANIC (1 << 4)
#define KEY_CAPSLOCK (1 << 5)
#define KEY_NUMLOCK (1 << 6)
#define KEY_COUNT_MASK (0x1F)
BBQ10Keyboard::BBQ10Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr) {}
void BBQ10Keyboard::begin(uint8_t addr, TwoWire *wire)
{
m_addr = addr;
m_wire = wire;
m_wire->begin();
reset();
}
void BBQ10Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
{
m_addr = addr;
m_wire = nullptr;
writeCallback = w;
readCallback = r;
reset();
}
void BBQ10Keyboard::reset()
{
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(_REG_RST);
m_wire->endTransmission();
}
if (writeCallback) {
uint8_t data = 0;
writeCallback(m_addr, _REG_RST, &data, 0);
}
delay(100);
writeRegister(_REG_CFG, readRegister8(_REG_CFG) | CFG_REPORT_MODS);
delay(100);
}
void BBQ10Keyboard::attachInterrupt(uint8_t pin, void (*func)(void)) const
{
pinMode(pin, INPUT_PULLUP);
::attachInterrupt(digitalPinToInterrupt(pin), func, RISING);
}
void BBQ10Keyboard::detachInterrupt(uint8_t pin) const
{
::detachInterrupt(pin);
}
void BBQ10Keyboard::clearInterruptStatus()
{
writeRegister(_REG_INT, 0x00);
}
uint8_t BBQ10Keyboard::status() const
{
return readRegister8(_REG_KEY);
}
uint8_t BBQ10Keyboard::keyCount() const
{
return status() & KEY_COUNT_MASK;
}
BBQ10Keyboard::KeyEvent BBQ10Keyboard::keyEvent() const
{
KeyEvent event = {.key = '\0', .state = StateIdle};
if (keyCount() == 0)
return event;
const uint16_t buf = readRegister16(_REG_FIF);
event.key = buf >> 8;
event.state = KeyState(buf & 0xFF);
return event;
}
float BBQ10Keyboard::backlight() const
{
return readRegister8(_REG_BKL) / 255.0f;
}
void BBQ10Keyboard::setBacklight(float value)
{
writeRegister(_REG_BKL, value * 255);
}
uint8_t BBQ10Keyboard::readRegister8(uint8_t reg) const
{
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, (uint8_t)1);
if (m_wire->available() < 1)
return 0;
return m_wire->read();
}
if (readCallback) {
uint8_t data;
readCallback(m_addr, reg, &data, 1);
return data;
}
return 0;
}
uint16_t BBQ10Keyboard::readRegister16(uint8_t reg) const
{
uint8_t data[2] = {0};
// uint8_t low = 0, high = 0;
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, (uint8_t)2);
if (m_wire->available() < 2)
return 0;
data[0] = m_wire->read();
data[1] = m_wire->read();
}
if (readCallback) {
readCallback(m_addr, reg, data, 2);
}
return (data[1] << 8) | data[0];
}
void BBQ10Keyboard::writeRegister(uint8_t reg, uint8_t value)
{
uint8_t data[2];
data[0] = reg | _WRITE_MASK;
data[1] = value;
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(data, sizeof(uint8_t) * 2);
m_wire->endTransmission();
}
if (writeCallback) {
writeCallback(m_addr, data[0], &(data[1]), 1);
}
}
+51
View File
@@ -0,0 +1,51 @@
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
#include "configuration.h"
#include <Wire.h>
#define KEY_MOD_ALT (0x1A)
#define KEY_MOD_SHL (0x1B)
#define KEY_MOD_SHR (0x1C)
#define KEY_MOD_SYM (0x1D)
class BBQ10Keyboard
{
public:
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
enum KeyState { StateIdle = 0, StatePress, StateLongPress, StateRelease };
struct KeyEvent {
char key;
KeyState state;
};
BBQ10Keyboard();
void begin(uint8_t addr = BBQ10_KB_ADDR, TwoWire *wire = &Wire);
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = BBQ10_KB_ADDR);
void reset(void);
void attachInterrupt(uint8_t pin, void (*func)(void)) const;
void detachInterrupt(uint8_t pin) const;
void clearInterruptStatus(void);
uint8_t status(void) const;
uint8_t keyCount(void) const;
KeyEvent keyEvent(void) const;
float backlight() const;
void setBacklight(float value);
uint8_t readRegister8(uint8_t reg) const;
uint16_t readRegister16(uint8_t reg) const;
void writeRegister(uint8_t reg, uint8_t value);
private:
TwoWire *m_wire;
uint8_t m_addr;
i2c_com_fptr_t readCallback;
i2c_com_fptr_t writeCallback;
};
+183
View File
@@ -0,0 +1,183 @@
#include "configuration.h"
#if ARCH_PORTDUINO
#include "LinuxInput.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
View File
@@ -0,0 +1,65 @@
#pragma once
#if ARCH_PORTDUINO
#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
+15
View File
@@ -0,0 +1,15 @@
#include "configuration.h"
#if ARCH_PORTDUINO
#include "InputBroker.h"
#include "LinuxInputImpl.h"
LinuxInputImpl *aLinuxInputImpl;
LinuxInputImpl::LinuxInputImpl() : LinuxInput("LinuxInput") {}
void LinuxInputImpl::init()
{
inputBroker->registerSource(this);
}
#endif
+21
View File
@@ -0,0 +1,21 @@
#ifdef ARCH_PORTDUINO
#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
+4 -3
View File
@@ -5,12 +5,12 @@ RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() : RotaryEncoderInterruptBase("rotEnc1") {} RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() : RotaryEncoderInterruptBase("rotEnc1") {}
void RotaryEncoderInterruptImpl1::init() bool RotaryEncoderInterruptImpl1::init()
{ {
if (!moduleConfig.canned_message.rotary1_enabled) { if (!moduleConfig.canned_message.rotary1_enabled) {
// Input device is disabled. // Input device is disabled.
disable(); disable();
return; return false;
} }
uint8_t pinA = moduleConfig.canned_message.inputbroker_pin_a; uint8_t pinA = moduleConfig.canned_message.inputbroker_pin_a;
@@ -25,6 +25,7 @@ void RotaryEncoderInterruptImpl1::init()
RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB, RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB,
RotaryEncoderInterruptImpl1::handleIntPressed); RotaryEncoderInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this); inputBroker->registerSource(this);
return true;
} }
void RotaryEncoderInterruptImpl1::handleIntA() void RotaryEncoderInterruptImpl1::handleIntA()
@@ -38,4 +39,4 @@ void RotaryEncoderInterruptImpl1::handleIntB()
void RotaryEncoderInterruptImpl1::handleIntPressed() void RotaryEncoderInterruptImpl1::handleIntPressed()
{ {
rotaryEncoderInterruptImpl1->intPressHandler(); rotaryEncoderInterruptImpl1->intPressHandler();
} }
+1 -1
View File
@@ -12,7 +12,7 @@ class RotaryEncoderInterruptImpl1 : public RotaryEncoderInterruptBase
{ {
public: public:
RotaryEncoderInterruptImpl1(); RotaryEncoderInterruptImpl1();
void init(); bool init();
static void handleIntA(); static void handleIntA();
static void handleIntB(); static void handleIntB();
static void handleIntPressed(); static void handleIntPressed();
+18 -2
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_PORTDUINO
#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_PORTDUINO
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:
+4 -3
View File
@@ -5,12 +5,12 @@ UpDownInterruptImpl1 *upDownInterruptImpl1;
UpDownInterruptImpl1::UpDownInterruptImpl1() : UpDownInterruptBase("upDown1") {} UpDownInterruptImpl1::UpDownInterruptImpl1() : UpDownInterruptBase("upDown1") {}
void UpDownInterruptImpl1::init() bool UpDownInterruptImpl1::init()
{ {
if (!moduleConfig.canned_message.updown1_enabled) { if (!moduleConfig.canned_message.updown1_enabled) {
// Input device is disabled. // Input device is disabled.
return; return false;
} }
uint8_t pinUp = moduleConfig.canned_message.inputbroker_pin_a; uint8_t pinUp = moduleConfig.canned_message.inputbroker_pin_a;
@@ -24,6 +24,7 @@ void UpDownInterruptImpl1::init()
UpDownInterruptBase::init(pinDown, pinUp, pinPress, eventDown, eventUp, eventPressed, UpDownInterruptImpl1::handleIntDown, UpDownInterruptBase::init(pinDown, pinUp, pinPress, eventDown, eventUp, eventPressed, UpDownInterruptImpl1::handleIntDown,
UpDownInterruptImpl1::handleIntUp, UpDownInterruptImpl1::handleIntPressed); UpDownInterruptImpl1::handleIntUp, UpDownInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this); inputBroker->registerSource(this);
return true;
} }
void UpDownInterruptImpl1::handleIntDown() void UpDownInterruptImpl1::handleIntDown()
@@ -37,4 +38,4 @@ void UpDownInterruptImpl1::handleIntUp()
void UpDownInterruptImpl1::handleIntPressed() void UpDownInterruptImpl1::handleIntPressed()
{ {
upDownInterruptImpl1->intPressHandler(); upDownInterruptImpl1->intPressHandler();
} }
+2 -2
View File
@@ -5,10 +5,10 @@ class UpDownInterruptImpl1 : public UpDownInterruptBase
{ {
public: public:
UpDownInterruptImpl1(); UpDownInterruptImpl1();
void init(); bool init();
static void handleIntDown(); static void handleIntDown();
static void handleIntUp(); static void handleIntUp();
static void handleIntPressed(); static void handleIntPressed();
}; };
extern UpDownInterruptImpl1 *upDownInterruptImpl1; extern UpDownInterruptImpl1 *upDownInterruptImpl1;
+1 -1
View File
@@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
void CardKbI2cImpl::init() void CardKbI2cImpl::init()
{ {
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) { if (cardkb_found.address == 0x00) {
disable(); disable();
return; return;
} }
+128 -11
View File
@@ -30,7 +30,7 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len
int32_t KbI2cBase::runOnce() int32_t KbI2cBase::runOnce()
{ {
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) { if (cardkb_found.address == 0x00) {
// Input device is not detected. // Input device is not detected.
return INT32_MAX; return INT32_MAX;
} }
@@ -41,11 +41,19 @@ int32_t KbI2cBase::runOnce()
#ifdef I2C_SDA1 #ifdef I2C_SDA1
LOG_DEBUG("Using I2C Bus 1 (the second one)\n"); LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
i2cBus = &Wire1; i2cBus = &Wire1;
if (cardkb_found.address == BBQ10_KB_ADDR) {
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire1);
Q10keyboard.setBacklight(0);
}
break; break;
#endif #endif
case ScanI2C::WIRE: case ScanI2C::WIRE:
LOG_DEBUG("Using I2C Bus 0 (the first one)\n"); LOG_DEBUG("Using I2C Bus 0 (the first one)\n");
i2cBus = &Wire; i2cBus = &Wire;
if (cardkb_found.address == BBQ10_KB_ADDR) {
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire);
Q10keyboard.setBacklight(0);
}
break; break;
case ScanI2C::NO_I2C: case ScanI2C::NO_I2C:
default: default:
@@ -53,7 +61,105 @@ int32_t KbI2cBase::runOnce()
} }
} }
if (kb_model == 0x02) { switch (kb_model) {
case 0x11: { // BB Q10
int keyCount = Q10keyboard.keyCount();
while (keyCount--) {
const BBQ10Keyboard::KeyEvent key = Q10keyboard.keyEvent();
if ((key.key != 0x00) && (key.state == BBQ10Keyboard::StateRelease)) {
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.source = this->_originName;
switch (key.key) {
case 'p': // TAB
case 't': // TAB as well
if (is_sym) {
e.inputEvent = ANYKEY;
e.kbchar = 0x09; // TAB Scancode
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 'q': // ESC
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.kbchar = 0x1b;
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 0x08: // Back
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.kbchar = key.key;
break;
case 'e': // sym e
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.kbchar = 0xb5;
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 'x': // sym x
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.kbchar = 0xb6;
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 's': // sym s
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = 0x00; // tweak for destSelect
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 'f': // sym f
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = 0x00; // tweak for destSelect
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.kbchar = key.key;
}
break;
case 0x13: // Code scanner says the SYM key is 0x13
is_sym = !is_sym;
break;
case 0x0a: // apparently Enter on Q10 is a line feed instead of carriage return
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
break;
case 0x00: // nopress
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
break;
default: // all other keys
e.inputEvent = ANYKEY;
e.kbchar = key.key;
is_sym = false; // reset sym state after second keypress
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
this->notifyObservers(&e);
}
}
}
break;
}
case 0x02: {
// RAK14004 // RAK14004
uint8_t rDataBuf[8] = {0}; uint8_t rDataBuf[8] = {0};
uint8_t PrintDataBuf = 0; uint8_t PrintDataBuf = 0;
@@ -74,11 +180,14 @@ int32_t KbI2cBase::runOnce()
e.kbchar = PrintDataBuf; e.kbchar = PrintDataBuf;
this->notifyObservers(&e); this->notifyObservers(&e);
} }
} else if (kb_model == 0x00 || kb_model == 0x10) { break;
// m5 cardkb and T-Deck }
i2cBus->requestFrom(kb_model == 0x00 ? CARDKB_ADDR : TDECK_KB_ADDR, 1); case 0x00: // CARDKB
case 0x10: { // T-DECK
while (i2cBus->available()) { i2cBus->requestFrom((int)cardkb_found.address, 1);
if (i2cBus->available()) {
char c = i2cBus->read(); char c = i2cBus->read();
InputEvent e; InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
@@ -93,17 +202,19 @@ int32_t KbI2cBase::runOnce()
break; break;
case 0xb5: // Up case 0xb5: // Up
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.kbchar = 0xb5;
break; break;
case 0xb6: // Down case 0xb6: // Down
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.kbchar = 0xb6;
break; break;
case 0xb4: // Left case 0xb4: // Left
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = c; e.kbchar = 0xb4;
break; break;
case 0xb7: // Right case 0xb7: // Right
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = c; e.kbchar = 0xb7;
break; break;
case 0x0d: // Enter case 0x0d: // Enter
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
@@ -111,7 +222,11 @@ int32_t KbI2cBase::runOnce()
case 0x00: // nopress case 0x00: // nopress
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
break; break;
default: // all other keys default: // all other keys
if (c > 127) { // bogus key value
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
break;
}
e.inputEvent = ANYKEY; e.inputEvent = ANYKEY;
e.kbchar = c; e.kbchar = c;
break; break;
@@ -121,8 +236,10 @@ int32_t KbI2cBase::runOnce()
this->notifyObservers(&e); this->notifyObservers(&e);
} }
} }
} else { break;
}
default:
LOG_WARN("Unknown kb_model 0x%02x\n", kb_model); LOG_WARN("Unknown kb_model 0x%02x\n", kb_model);
} }
return 300; return 300;
} }
+4
View File
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "BBQ10Keyboard.h"
#include "InputBroker.h" #include "InputBroker.h"
#include "Wire.h" #include "Wire.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
@@ -16,4 +17,7 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
const char *_originName; const char *_originName;
TwoWire *i2cBus = 0; TwoWire *i2cBus = 0;
BBQ10Keyboard Q10keyboard;
bool is_sym = false;
}; };
+240 -61
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,13 +66,27 @@ NRF52Bluetooth *nrf52Bluetooth;
#include "platform/portduino/SimRadio.h" #include "platform/portduino/SimRadio.h"
#endif #endif
#if HAS_BUTTON #ifdef ARCH_PORTDUINO
#include "linux/LinuxHardwareI2C.h"
#include "platform/portduino/PortduinoGlue.h"
#include <fstream>
#include <iostream>
#include <string>
#endif
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
#include "ButtonThread.h" #include "ButtonThread.h"
#endif #endif
#include "PowerFSMThread.h" #include "PowerFSMThread.h"
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "AccelerometerThread.h" #include "AccelerometerThread.h"
#include "AmbientLightingThread.h"
#endif
#ifdef HAS_I2S
#include "AudioThread.h"
AudioThread *audioThread;
#endif #endif
using namespace concurrency; using namespace concurrency;
@@ -113,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;
@@ -121,9 +136,8 @@ 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
@@ -145,6 +159,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;
@@ -158,17 +191,18 @@ static int32_t ledBlinker()
uint32_t timeLastPowered = 0; uint32_t timeLastPowered = 0;
#if HAS_BUTTON #if HAS_BUTTON || defined(ARCH_PORTDUINO)
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_PORTDUINO)
static OSThread *buttonThread; static OSThread *buttonThread;
uint32_t ButtonThread::longPressTime = 0; uint32_t ButtonThread::longPressTime = 0;
#endif #endif
static OSThread *accelerometerThread; static OSThread *accelerometerThread;
static OSThread *ambientLightingThread;
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0); SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
RadioInterface *rIf = NULL; RadioInterface *rIf = NULL;
@@ -214,12 +248,64 @@ void setup()
digitalWrite(PIN_EINK_PWR_ON, HIGH); digitalWrite(PIN_EINK_PWR_ON, HIGH);
#endif #endif
#ifdef VEXT_ENABLE #if defined(LORA_TCXO_GPIO)
pinMode(LORA_TCXO_GPIO, OUTPUT);
digitalWrite(LORA_TCXO_GPIO, HIGH);
#endif
#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
#ifdef VGNSS_CTRL #if defined(VGNSS_CTRL_V03)
if (heltec_version == 3) {
pinMode(VGNSS_CTRL_V03, OUTPUT);
digitalWrite(VGNSS_CTRL_V03, LOW);
} else {
pinMode(VGNSS_CTRL_V05, OUTPUT);
digitalWrite(VGNSS_CTRL_V05, LOW);
}
#endif
#if defined(VTFT_CTRL_V03)
if (heltec_version == 3) {
pinMode(VTFT_CTRL_V03, OUTPUT);
digitalWrite(VTFT_CTRL_V03, LOW);
} else {
pinMode(VTFT_CTRL_V05, OUTPUT);
digitalWrite(VTFT_CTRL_V05, LOW);
}
#endif
#if defined(VGNSS_CTRL)
pinMode(VGNSS_CTRL, OUTPUT); pinMode(VGNSS_CTRL, OUTPUT);
digitalWrite(VGNSS_CTRL, LOW); digitalWrite(VGNSS_CTRL, LOW);
#endif #endif
@@ -268,12 +354,27 @@ 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 defined(ARCH_PORTDUINO)
if (settingsStrings[i2cdev] != "") {
LOG_INFO("Using %s as I2C device.\n", settingsStrings[i2cdev]);
Wire.begin(settingsStrings[i2cdev].c_str());
} else {
LOG_INFO("No I2C device configured, skipping.\n");
}
#elif HAS_WIRE #elif HAS_WIRE
Wire.begin(); Wire.begin();
#endif #endif
@@ -319,17 +420,33 @@ void setup()
// We need to scan here to decide if we have a screen for nodeDB.init() and because power has been applied to // We need to scan here to decide if we have a screen for nodeDB.init() and because power has been applied to
// accessories // accessories
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire()); auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
#ifdef HAS_WIRE
LOG_INFO("Scanning for i2c devices...\n"); LOG_INFO("Scanning for i2c devices...\n");
#endif
#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 defined(ARCH_PORTDUINO)
if (settingsStrings[i2cdev] != "") {
LOG_INFO("Scanning for i2c devices...\n");
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
}
#elif HAS_WIRE #elif HAS_WIRE
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE); i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#endif #endif
@@ -337,6 +454,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);
} }
@@ -387,6 +508,10 @@ void setup()
// assign an arbitrary value to distinguish from other models // assign an arbitrary value to distinguish from other models
kb_model = 0x10; kb_model = 0x10;
break; break;
case ScanI2C::DeviceType::BBQ10KB:
// assign an arbitrary value to distinguish from other models
kb_model = 0x11;
break;
default: default:
// use this as default since it's also just zero // use this as default since it's also just zero
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type);
@@ -405,14 +530,6 @@ void setup()
// Only one supported RGB LED currently // Only one supported RGB LED currently
#ifdef HAS_NCP5623 #ifdef HAS_NCP5623
rgb_found = i2cScanner->find(ScanI2C::DeviceType::NCP5623); rgb_found = i2cScanner->find(ScanI2C::DeviceType::NCP5623);
// Start the RGB LED at 50%
if (rgb_found.type == ScanI2C::NCP5623) {
rgb.begin();
rgb.setCurrent(10);
rgb.setColor(128, 128, 128);
}
#endif #endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
@@ -427,7 +544,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)); \
} \ } \
} }
@@ -437,6 +555,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)
@@ -483,13 +602,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_PORTDUINO)
// 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
@@ -517,6 +639,12 @@ void setup()
} }
#endif #endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
if (rgb_found.type != ScanI2C::DeviceType::NONE) {
ambientLightingThread = new AmbientLightingThread(rgb_found.type);
}
#endif
#ifdef T_WATCH_S3 #ifdef T_WATCH_S3
drv.begin(); drv.begin();
drv.selectLibrary(1); drv.selectLibrary(1);
@@ -528,24 +656,26 @@ 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 ARCH_PORTDUINO
SPI.begin(settingsStrings[spidev].c_str());
#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
@@ -554,16 +684,23 @@ 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 = createGps(); // If we're taking on the repeater role, ignore GPS
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER &&
config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) {
gps = GPS::createGps();
}
if (gps) { if (gps) {
gpsStatus->observe(&gps->newStatus); gpsStatus->observe(&gps->newStatus);
} else { } else {
LOG_WARN("No GPS found - running without GPS\n"); LOG_DEBUG("Running without GPS.\n");
} }
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
@@ -579,6 +716,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 defined(ARCH_PORTDUINO)
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();
@@ -586,24 +727,60 @@ void setup()
screen->print("Started...\n"); screen->print("Started...\n");
// We have now loaded our saved preferences from flash
// ONCE we will factory reset the GPS for bug #327
if (gps && !devicestate.did_gps_reset) {
LOG_WARN("GPS FactoryReset requested\n");
if (gps->factoryReset()) { // If we don't succeed try again next time
devicestate.did_gps_reset = true;
nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
}
}
#ifdef SX126X_ANT_SW #ifdef SX126X_ANT_SW
// make analog PA vs not PA switch on SX126x eval board work properly // make analog PA vs not PA switch on SX126x eval board work properly
pinMode(SX126X_ANT_SW, OUTPUT); pinMode(SX126X_ANT_SW, OUTPUT);
digitalWrite(SX126X_ANT_SW, 1); digitalWrite(SX126X_ANT_SW, 1);
#endif #endif
#ifdef HW_SPI1_DEVICE #ifdef ARCH_PORTDUINO
if (settingsMap[use_sx1262]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1262 radio on SPI port %s\n", settingsStrings[spidev].c_str());
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) {
LOG_DEBUG("Attempting to activate rf95 radio on SPI port %s\n", settingsStrings[spidev].c_str());
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) {
LOG_DEBUG("Attempting to activate sx1280 radio on SPI port %s\n", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
LOG_ERROR("Failed to find SX1280 radio\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);
@@ -638,7 +815,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;
@@ -649,7 +826,7 @@ void setup()
} }
#endif #endif
#if defined(USE_SX1262) #if defined(USE_SX1262) && !defined(ARCH_PORTDUINO)
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()) {
@@ -718,11 +895,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.
@@ -750,8 +931,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();
// setBluetoothEnable(false); we now don't start bluetooth until we enter the proper state
setCPUFast(false); // 80MHz is fine for our slow peripherals setCPUFast(false); // 80MHz is fine for our slow peripherals
} }
+9 -1
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
@@ -64,11 +70,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();
+6 -33
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"
@@ -14,6 +15,7 @@ Channels channels;
const char *Channels::adminChannel = "admin"; const char *Channels::adminChannel = "admin";
const char *Channels::gpioChannel = "gpio"; const char *Channels::gpioChannel = "gpio";
const char *Channels::serialChannel = "serial"; const char *Channels::serialChannel = "serial";
const char *Channels::mqttChannel = "mqtt";
uint8_t xorHash(const uint8_t *p, size_t len) uint8_t xorHash(const uint8_t *p, size_t len)
{ {
@@ -183,7 +185,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 +241,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";
} }
@@ -341,4 +314,4 @@ bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
int16_t Channels::setActiveByIndex(ChannelIndex channelIndex) int16_t Channels::setActiveByIndex(ChannelIndex channelIndex)
{ {
return setCrypto(channelIndex); return setCrypto(channelIndex);
} }
+2 -2
View File
@@ -32,7 +32,7 @@ class Channels
Channels() {} Channels() {}
/// Well known channel names /// Well known channel names
static const char *adminChannel, *gpioChannel, *serialChannel; static const char *adminChannel, *gpioChannel, *serialChannel, *mqttChannel;
const meshtastic_ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; } const meshtastic_ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; }
@@ -139,4 +139,4 @@ class Channels
}; };
/// Singleton channel table /// Singleton channel table
extern Channels channels; extern Channels channels;
-55
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;
}
};
+43 -18
View File
@@ -108,8 +108,9 @@ void MeshService::loop()
(void)sendQueueStatusToPhone(qs, 0, 0); (void)sendQueueStatusToPhone(qs, 0, 0);
} }
if (oldFromNum != fromNum) { // We don't want to generate extra notifies for multiple new packets if (oldFromNum != fromNum) { // We don't want to generate extra notifies for multiple new packets
fromNumChanged.notifyObservers(fromNum); int result = fromNumChanged.notifyObservers(fromNum);
oldFromNum = fromNum; if (result == 0) // If any observer returns non-zero, we will try again
oldFromNum = fromNum;
} }
} }
@@ -140,6 +141,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 +284,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 +337,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;
} }
@@ -327,21 +354,19 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
// load data from GPS object, will add timestamp + battery further down // load data from GPS object, will add timestamp + battery further down
pos = gps->p; pos = gps->p;
} else { } else {
// The GPS has lost lock, if we are fixed position we should just keep using // The GPS has lost lock
// the old position
#ifdef GPS_EXTRAVERBOSE #ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("onGPSchanged() - lost validLocation\n"); LOG_DEBUG("onGPSchanged() - lost validLocation\n");
#endif #endif
if (config.position.fixed_position) { }
LOG_WARN("Using fixed position\n"); // Used fixed position if configured regalrdless of GPS lock
pos = ConvertToPosition(node->position); if (config.position.fixed_position) {
} LOG_WARN("Using fixed position\n");
pos = TypeConversions::ConvertToPosition(node->position);
} }
// Finally add a fresh timestamp and battery level reading // Add a fresh timestamp
// I KNOW this is redundant with refreshLocalMeshNode() above, but these are pos.time = getValidTime(RTCQualityFromNet);
// inexpensive nonblocking calls and can be refactored in due course
pos.time = getValidTime(RTCQualityGPS);
// In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB) // In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB)
LOG_DEBUG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i, LOG_DEBUG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i,
+13 -2
View File
@@ -48,6 +48,14 @@ class MeshService
uint32_t oldFromNum = 0; uint32_t oldFromNum = 0;
public: public:
static bool isTextPayload(const meshtastic_MeshPacket *p)
{
if (moduleConfig.range_test.enabled && p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) {
return true;
}
return p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
p->decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP;
}
/// Called when some new packets have arrived from one of the radios /// Called when some new packets have arrived from one of the radios
Observable<uint32_t> fromNumChanged; Observable<uint32_t> fromNumChanged;
@@ -74,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); }
@@ -118,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
@@ -127,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;
+139 -37
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_PORTDUINO
#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>
@@ -169,7 +173,25 @@ void NodeDB::installDefaultConfig()
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET; config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST; config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
config.lora.hop_limit = HOP_RELIABLE; config.lora.hop_limit = HOP_RELIABLE;
config.position.gps_enabled = true; config.lora.ignore_mqtt = false;
#ifdef PIN_GPS_EN
config.position.gps_en_gpio = PIN_GPS_EN;
#endif
#ifdef GPS_POWER_TOGGLE
config.device.disable_triple_click = false;
#else
config.device.disable_triple_click = true;
#endif
#if !HAS_GPS || defined(T_DECK)
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
#elif !defined(GPS_RX_PIN)
if (config.position.rx_gpio == 0)
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
else
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
#else
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
#endif
config.position.position_broadcast_smart_enabled = true; config.position.position_broadcast_smart_enabled = true;
config.position.broadcast_smart_minimum_distance = 100; config.position.broadcast_smart_minimum_distance = 100;
config.position.broadcast_smart_minimum_interval_secs = 30; config.position.broadcast_smart_minimum_interval_secs = 30;
@@ -183,6 +205,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_PORTDUINO
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
@@ -190,7 +218,9 @@ void NodeDB::installDefaultConfig()
: meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN; : meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
// for backward compat, default position flags are ALT+MSL // for backward compat, default position flags are ALT+MSL
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_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;
@@ -203,7 +233,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;
@@ -235,19 +264,42 @@ 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;
moduleConfig.has_detection_sensor = true;
moduleConfig.detection_sensor.enabled = false;
moduleConfig.detection_sensor.detection_triggered_high = true;
moduleConfig.detection_sensor.minimum_broadcast_secs = 45;
moduleConfig.has_ambient_lighting = true;
moduleConfig.ambient_lighting.current = 10;
// Default to a color based on our node number
moduleConfig.ambient_lighting.red = (myNodeInfo.my_node_num & 0xFF0000) >> 16;
moduleConfig.ambient_lighting.green = (myNodeInfo.my_node_num & 0x00FF00) >> 8;
moduleConfig.ambient_lighting.blue = myNodeInfo.my_node_num & 0x0000FF;
initModuleConfigIntervals(); initModuleConfigIntervals();
} }
@@ -258,11 +310,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;
} }
} }
@@ -283,13 +354,40 @@ 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()
{
int newPos = 0, removed = 0;
for (int i = 0; i < *numMeshNodes; i++) {
if (meshNodes[i].has_user)
meshNodes[newPos++] = meshNodes[i];
else
removed++;
}
*numMeshNodes -= removed;
LOG_DEBUG("cleanupMeshDB purged %d entries\n", removed);
}
void NodeDB::installDefaultDeviceState() void NodeDB::installDefaultDeviceState()
{ {
LOG_INFO("Installing default DeviceState\n"); LOG_INFO("Installing default DeviceState\n");
@@ -310,7 +408,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));
} }
@@ -319,6 +416,7 @@ void NodeDB::init()
{ {
LOG_INFO("Initializing NodeDB\n"); LOG_INFO("Initializing NodeDB\n");
loadFromDisk(); loadFromDisk();
cleanupMeshDB();
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate)); uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
uint32_t configCRC = crc32Buffer(&config, sizeof(config)); uint32_t configCRC = crc32Buffer(&config, sizeof(config));
@@ -334,6 +432,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());
@@ -363,6 +463,11 @@ void NodeDB::init()
memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty)); memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty));
} }
if (config.position.gps_enabled) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
config.position.gps_enabled = 0;
}
saveToDisk(saveWhat); saveToDisk(saveWhat);
} }
@@ -374,25 +479,22 @@ void NodeDB::init()
*/ */
void NodeDB::pickNewNodeNum() void NodeDB::pickNewNodeNum()
{ {
NodeNum r = myNodeInfo.my_node_num;
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
// Pick an initial nodenum based on the macaddr // Pick an initial nodenum based on the macaddr
r = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5]; NodeNum nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
if (r == NODENUM_BROADCAST || r < NUM_RESERVED)
r = NUM_RESERVED; // don't pick a reserved node number
meshtastic_NodeInfoLite *found; meshtastic_NodeInfoLite *found;
while ((found = getMeshNode(r)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr))) { while ((nodeNum == NODENUM_BROADCAST || nodeNum < NUM_RESERVED) ||
// FIXME: input for random() is int, so NODENUM_BROADCAST becomes -1 ((found = getMeshNode(nodeNum)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr)) != 0)) {
NodeNum n = random(NUM_RESERVED, NODENUM_BROADCAST); // try a new random choice NodeNum candidate = random(NUM_RESERVED, LONG_MAX); // try a new random choice
LOG_WARN("NOTE! Our desired nodenum 0x%x is in use, so trying for 0x%x\n", r, n); LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, so trying for 0x%x\n", nodeNum, candidate);
r = n; nodeNum = candidate;
} }
LOG_WARN("Using nodenum 0x%x \n", nodeNum);
myNodeInfo.my_node_num = r; myNodeInfo.my_node_num = nodeNum;
} }
static const char *prefFileName = "/prefs/db.proto"; static const char *prefFileName = "/prefs/db.proto";
@@ -656,8 +758,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)
@@ -675,7 +777,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)
@@ -709,22 +811,25 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS
notifyObservers(true); // Force an update whether or not our node counts have changed notifyObservers(true); // Force an update whether or not our node counts have changed
} }
/** Update user info for this node based on received user data /** Update user info and channel for this node based on received user data
*/ */
bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p) bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p, uint8_t channelIndex)
{ {
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId);
if (!info) { if (!info) {
return false; return false;
} }
LOG_DEBUG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name); LOG_DEBUG("old user %s/%s/%s, channel=%d\n", info->user.id, info->user.long_name, info->user.short_name, info->channel);
bool changed = memcmp(&info->user, &p, // Both of info->user and p start as filled with zero so I think this is okay
sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay bool changed = memcmp(&info->user, &p, sizeof(info->user)) || (info->channel != channelIndex);
info->user = p; info->user = p;
LOG_DEBUG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name); if (nodeId != getNodeNum())
info->channel = channelIndex; // Set channel we need to use to reach this node (but don't set our own channel)
LOG_DEBUG("updating changed=%d user %s/%s/%s, channel=%d\n", changed, info->user.id, info->user.long_name,
info->user.short_name, info->channel);
info->has_user = true; info->has_user = true;
if (changed) { if (changed) {
@@ -744,7 +849,7 @@ bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p)
void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
{ {
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) { if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
LOG_DEBUG("Update DB node 0x%x, rx_time=%u, channel=%d\n", mp.from, mp.rx_time, mp.channel); LOG_DEBUG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getFrom(&mp)); meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getFrom(&mp));
if (!info) { if (!info) {
@@ -756,10 +861,6 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
if (mp.rx_snr) if (mp.rx_snr)
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node. info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
if (mp.decoded.portnum == meshtastic_PortNum_NODEINFO_APP) {
info->channel = mp.channel;
}
} }
} }
@@ -792,10 +893,11 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) { if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
if (screen) if (screen)
screen->print("warning: node_db_lite full! erasing oldest entry\n"); screen->print("warning: node_db_lite full! erasing oldest entry\n");
LOG_INFO("warning: node_db_lite full! erasing oldest entry\n");
// look for oldest node and erase it // look for oldest node and erase it
uint32_t oldest = UINT32_MAX; uint32_t oldest = UINT32_MAX;
int oldestIndex = -1; int oldestIndex = -1;
for (int i = 0; i < *numMeshNodes; i++) { for (int i = 1; i < *numMeshNodes; i++) {
if (meshNodes[i].last_heard < oldest) { if (meshNodes[i].last_heard < oldest) {
oldest = meshNodes[i].last_heard; oldest = meshNodes[i].last_heard;
oldestIndex = i; oldestIndex = i;
+23 -8
View File
@@ -84,9 +84,9 @@ class NodeDB
*/ */
void updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxSource src = RX_SRC_RADIO); void updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxSource src = RX_SRC_RADIO);
/** Update user info for this node based on received user data /** Update user info and channel for this node based on received user data
*/ */
bool updateUser(uint32_t nodeId, const meshtastic_User &p); bool updateUser(uint32_t nodeId, const meshtastic_User &p, uint8_t channelIndex = 0);
/// @return our node number /// @return our node number
NodeNum getNodeNum() { return myNodeInfo.my_node_num; } NodeNum getNodeNum() { return myNodeInfo.my_node_num; }
@@ -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);
@@ -146,6 +153,9 @@ class NodeDB
/// read our db from flash /// read our db from flash
void loadFromDisk(); void loadFromDisk();
/// purge db entries without user info
void cleanupMeshDB();
/// Reinit device state from scratch (not loading from disk) /// Reinit device state from scratch (not loading from disk)
void installDefaultDeviceState(), installDefaultChannels(), installDefaultConfig(), installDefaultModuleConfig(); void installDefaultDeviceState(), installDefaultChannels(), installDefaultConfig(), installDefaultModuleConfig();
}; };
@@ -169,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
@@ -182,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)
{ {
@@ -209,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)
+2 -2
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
+29 -12
View File
@@ -62,15 +62,17 @@ void PhoneAPI::close()
} }
} }
void PhoneAPI::checkConnectionTimeout() bool PhoneAPI::checkConnectionTimeout()
{ {
if (isConnected()) { if (isConnected()) {
bool newContact = checkIsConnected(); bool newContact = checkIsConnected();
if (!newContact) { if (!newContact) {
LOG_INFO("Lost phone connection\n"); LOG_INFO("Lost phone connection\n");
close(); close();
return true;
} }
} }
return false;
} }
/** /**
@@ -155,11 +157,18 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// app not to send locations on our behalf. // app not to send locations on our behalf.
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag; fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag;
fromRadioScratch.my_info = myNodeInfo; fromRadioScratch.my_info = myNodeInfo;
state = STATE_SEND_NODEINFO; state = STATE_SEND_METADATA;
service.refreshLocalMeshNode(); // Update my NodeInfo because the client will be asking for it soon. service.refreshLocalMeshNode(); // Update my NodeInfo because the client will be asking for it soon.
break; break;
case STATE_SEND_METADATA:
LOG_INFO("getFromRadio=STATE_SEND_METADATA\n");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag;
fromRadioScratch.metadata = getDeviceMetadata();
state = STATE_SEND_NODEINFO;
break;
case STATE_SEND_NODEINFO: { case STATE_SEND_NODEINFO: {
LOG_INFO("getFromRadio=STATE_SEND_NODEINFO\n"); LOG_INFO("getFromRadio=STATE_SEND_NODEINFO\n");
@@ -283,6 +292,18 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag; fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag;
fromRadioScratch.moduleConfig.payload_variant.neighbor_info = moduleConfig.neighbor_info; fromRadioScratch.moduleConfig.payload_variant.neighbor_info = moduleConfig.neighbor_info;
break; break;
case meshtastic_ModuleConfig_detection_sensor_tag:
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
fromRadioScratch.moduleConfig.payload_variant.detection_sensor = moduleConfig.detection_sensor;
break;
case meshtastic_ModuleConfig_ambient_lighting_tag:
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag;
fromRadioScratch.moduleConfig.payload_variant.ambient_lighting = moduleConfig.ambient_lighting;
break;
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);
} }
@@ -290,15 +311,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
config_state++; config_state++;
// Advance when we have sent all of our ModuleConfig objects // Advance when we have sent all of our ModuleConfig objects
if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) { if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) {
state = STATE_SEND_METADATA; state = STATE_SEND_COMPLETE_ID;
config_state = 0; config_state = 0;
} }
break; break;
case STATE_SEND_METADATA:
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag;
fromRadioScratch.metadata = getDeviceMetadata();
state = STATE_SEND_COMPLETE_ID;
break;
case STATE_SEND_COMPLETE_ID: case STATE_SEND_COMPLETE_ID:
LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n"); LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag; fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag;
@@ -398,7 +415,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
@@ -446,8 +463,8 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
/// If the mesh service tells us fromNum has changed, tell the phone /// If the mesh service tells us fromNum has changed, tell the phone
int PhoneAPI::onNotify(uint32_t newValue) int PhoneAPI::onNotify(uint32_t newValue)
{ {
checkConnectionTimeout(); // a handy place to check if we've heard from the phone (since the BLE version doesn't call this bool timeout = checkConnectionTimeout(); // a handy place to check if we've heard from the phone (since the BLE version
// from idle) // doesn't call this from idle)
if (state == STATE_SEND_PACKETS) { if (state == STATE_SEND_PACKETS) {
LOG_INFO("Telling client we have new packets %u\n", newValue); LOG_INFO("Telling client we have new packets %u\n", newValue);
@@ -456,5 +473,5 @@ int PhoneAPI::onNotify(uint32_t newValue)
LOG_DEBUG("(Client not yet interested in packets)\n"); LOG_DEBUG("(Client not yet interested in packets)\n");
} }
return 0; return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one
} }
+3 -3
View File
@@ -108,8 +108,8 @@ class PhoneAPI
/// Hookable to find out when connection changes /// Hookable to find out when connection changes
virtual void onConnectionChanged(bool connected) {} virtual void onConnectionChanged(bool connected) {}
/// If we haven't heard from the other side in a while then say not connected /// If we haven't heard from the other side in a while then say not connected. Returns true if timeout occurred
void checkConnectionTimeout(); bool checkConnectionTimeout();
/// 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() = 0; virtual bool checkIsConnected() = 0;
@@ -142,4 +142,4 @@ class PhoneAPI
/// If the mesh service tells us fromNum has changed, tell the phone /// If the mesh service tells us fromNum has changed, tell the phone
virtual int onNotify(uint32_t newValue) override; virtual int onNotify(uint32_t newValue) override;
}; };
+23 -4
View File
@@ -4,6 +4,10 @@
#include "configuration.h" #include "configuration.h"
#include "error.h" #include "error.h"
#if ARCH_PORTDUINO
#include "PortduinoGlue.h"
#endif
#define MAX_POWER 20 #define MAX_POWER 20
// if we use 20 we are limited to 1% duty cycle or hw might overheat. For continuous operation set a limit of 17 // if we use 20 we are limited to 1% duty cycle or hw might overheat. For continuous operation set a limit of 17
// In theory up to 27 dBm is possible, but the modules installed in most radios can cope with a max of 20. So BIG WARNING // In theory up to 27 dBm is possible, but the modules installed in most radios can cope with a max of 20. So BIG WARNING
@@ -23,10 +27,18 @@ void RF95Interface::setTransmitEnable(bool txon)
{ {
#ifdef RF95_TXEN #ifdef RF95_TXEN
digitalWrite(RF95_TXEN, txon ? 1 : 0); digitalWrite(RF95_TXEN, txon ? 1 : 0);
#elif ARCH_PORTDUINO
if (settingsMap[txen] != RADIOLIB_NC) {
digitalWrite(settingsMap[txen], txon ? 1 : 0);
}
#endif #endif
#ifdef RF95_RXEN #ifdef RF95_RXEN
digitalWrite(RF95_RXEN, txon ? 0 : 1); digitalWrite(RF95_RXEN, txon ? 0 : 1);
#elif ARCH_PORTDUINO
if (settingsMap[rxen] != RADIOLIB_NC) {
digitalWrite(settingsMap[rxen], txon ? 0 : 1);
}
#endif #endif
} }
@@ -37,9 +49,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;
@@ -65,6 +74,16 @@ bool RF95Interface::init()
#ifdef RF95_RXEN #ifdef RF95_RXEN
pinMode(RF95_RXEN, OUTPUT); pinMode(RF95_RXEN, OUTPUT);
digitalWrite(RF95_RXEN, 1); digitalWrite(RF95_RXEN, 1);
#endif
#if ARCH_PORTDUINO
if (settingsMap[txen] != RADIOLIB_NC) {
pinMode(settingsMap[txen], OUTPUT);
digitalWrite(settingsMap[txen], 0);
}
if (settingsMap[rxen] != RADIOLIB_NC) {
pinMode(settingsMap[rxen], OUTPUT);
digitalWrite(settingsMap[rxen], 0);
}
#endif #endif
setTransmitEnable(false); setTransmitEnable(false);
@@ -205,4 +224,4 @@ bool RF95Interface::sleep()
lora->sleep(); lora->sleep();
return true; return true;
} }
+34 -18
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),
/* /*
@@ -272,15 +287,14 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p)
out += " encrypted"; out += " encrypted";
} }
if (p->rx_time != 0) { if (p->rx_time != 0)
out += DEBUG_PORT.mt_sprintf(" rxtime=%u", p->rx_time); out += DEBUG_PORT.mt_sprintf(" rxtime=%u", p->rx_time);
} if (p->rx_snr != 0.0)
if (p->rx_snr != 0.0) {
out += DEBUG_PORT.mt_sprintf(" rxSNR=%g", p->rx_snr); out += DEBUG_PORT.mt_sprintf(" rxSNR=%g", p->rx_snr);
} if (p->rx_rssi != 0)
if (p->rx_rssi != 0) {
out += DEBUG_PORT.mt_sprintf(" rxRSSI=%i", p->rx_rssi); out += DEBUG_PORT.mt_sprintf(" rxRSSI=%i", p->rx_rssi);
} if (p->via_mqtt != 0)
out += DEBUG_PORT.mt_sprintf(" via MQTT");
if (p->priority != 0) if (p->priority != 0)
out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority); out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority);
@@ -328,9 +342,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 +398,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 +462,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
@@ -534,10 +550,10 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
h->id = p->id; h->id = p->id;
h->channel = p->channel; h->channel = p->channel;
if (p->hop_limit > HOP_MAX) { if (p->hop_limit > HOP_MAX) {
LOG_WARN("hop limit %d is too high, setting to %d\n", p->hop_limit, HOP_MAX); LOG_WARN("hop limit %d is too high, setting to %d\n", p->hop_limit, HOP_RELIABLE);
p->hop_limit = HOP_MAX; p->hop_limit = HOP_RELIABLE;
} }
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0); h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0) | (p->via_mqtt ? PACKET_FLAGS_VIA_MQTT_MASK : 0);
// if the sender nodenum is zero, that means uninitialized // if the sender nodenum is zero, that means uninitialized
assert(h->from); assert(h->from);
+2 -1
View File
@@ -12,6 +12,7 @@
#define PACKET_FLAGS_HOP_MASK 0x07 #define PACKET_FLAGS_HOP_MASK 0x07
#define PACKET_FLAGS_WANT_ACK_MASK 0x08 #define PACKET_FLAGS_WANT_ACK_MASK 0x08
#define PACKET_FLAGS_VIA_MQTT_MASK 0x10
/** /**
* This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility * This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility
@@ -56,7 +57,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);
+2 -1
View File
@@ -362,6 +362,7 @@ void RadioLibInterface::handleReceiveInterrupt()
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK; mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK); mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
mp->via_mqtt = !!(h->flags & PACKET_FLAGS_VIA_MQTT_MASK);
addReceiveMetadata(mp); addReceiveMetadata(mp);
@@ -406,4 +407,4 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
// bits // bits
enableInterrupt(isrTxLevel0); enableInterrupt(isrTxLevel0);
} }
} }
+4 -7
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
@@ -25,7 +21,7 @@ int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_
LOG_DEBUG("Current limit set result %d\n", state); LOG_DEBUG("Current limit set result %d\n", state);
// configure settings not accessible by API // configure settings not accessible by API
state = config(); // state = config();
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
#ifdef RF95_TCXO #ifdef RF95_TCXO
@@ -79,5 +75,6 @@ bool RadioLibRF95::isReceiving()
uint8_t RadioLibRF95::readReg(uint8_t addr) uint8_t RadioLibRF95::readReg(uint8_t addr)
{ {
Module *mod = this->getMod();
return mod->SPIreadRegister(addr); return mod->SPIreadRegister(addr);
} }
+15 -33
View File
@@ -248,45 +248,21 @@ ErrorCode Router::send(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) {
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
meshtastic_MeshPacket *p_decoded = packetPool.allocCopy(*p);
bool shouldActuallyEncrypt = true;
if (moduleConfig.mqtt.enabled) {
// check if we should send decrypted packets to mqtt
// truth table:
/* mqtt_server mqtt_encryption_enabled should_encrypt
* not set 0 1
* not set 1 1
* set 0 0
* set 1 1
*
* => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE
*/
if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) {
shouldActuallyEncrypt = false;
}
LOG_INFO("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt);
// the packet is currently in a decrypted state. send it now if they want decrypted packets
if (mqtt && !shouldActuallyEncrypt)
mqtt->onSend(*p, chIndex);
}
auto encodeResult = perhapsEncode(p); auto encodeResult = perhapsEncode(p);
if (encodeResult != meshtastic_Routing_Error_NONE) { if (encodeResult != meshtastic_Routing_Error_NONE) {
packetPool.release(p_decoded);
abortSendAndNak(encodeResult, p); abortSendAndNak(encodeResult, p);
return encodeResult; // FIXME - this isn't a valid ErrorCode return encodeResult; // FIXME - this isn't a valid ErrorCode
} }
if (moduleConfig.mqtt.enabled) { if (moduleConfig.mqtt.enabled) {
// the packet is now encrypted. LOG_INFO("Should encrypt MQTT?: %d\n", moduleConfig.mqtt.encryption_enabled);
// check if we should send encrypted packets to mqtt if (mqtt)
if (mqtt && shouldActuallyEncrypt) mqtt->onSend(*p, *p_decoded, chIndex);
mqtt->onSend(*p, chIndex);
} }
packetPool.release(p_decoded);
} }
assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside) assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside)
@@ -316,6 +292,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
@@ -478,10 +460,10 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
{ {
// assert(radioConfig.has_preferences); // assert(radioConfig.has_preferences);
bool ignore = is_in_repeated(config.lora.ignore_incoming, p->from); bool ignore = is_in_repeated(config.lora.ignore_incoming, p->from) || (config.lora.ignore_mqtt && p->via_mqtt);
if (ignore) { if (ignore) {
LOG_DEBUG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from); LOG_DEBUG("Ignoring incoming message, 0x%x is in our ignore list or came via MQTT\n", p->from);
} else if (ignore |= shouldFilterReceived(p)) { } else if (ignore |= shouldFilterReceived(p)) {
LOG_DEBUG("Incoming message was filtered 0x%x\n", p->from); LOG_DEBUG("Incoming message was filtered 0x%x\n", p->from);
} }
@@ -492,4 +474,4 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
handleReceived(p); handleReceived(p);
packetPool.release(p); packetPool.release(p);
} }
-3
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;
+69 -46
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_PORTDUINO
#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,35 @@ 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 #if ARCH_PORTDUINO
float tcxoVoltage = 0; // None - we use an XTAL float tcxoVoltage = 0;
if (settingsMap[dio3_tcxo_voltage])
tcxoVoltage = 1.8;
// FIXME: correct logic to default to not using TCXO if no voltage is specified for SX126X_DIO3_TCXO_VOLTAGE
#elif !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)
#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; // (DIO3 is not free to be used as an IRQ)
#endif #endif
if (tcxoVoltage == 0)
LOG_DEBUG("SX126X_DIO3_TCXO_VOLTAGE not defined, not using DIO3 as TCXO reference voltage\n");
else
LOG_DEBUG("SX126X_DIO3_TCXO_VOLTAGE defined, using DIO3 as TCXO reference voltage at %f V\n", tcxoVoltage);
// 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 +69,62 @@ 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_PORTDUINO)
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 defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
// If SX126X_TXEN is connected to the MCU, we are manually controlling RX and TX.
// But lora.begin (called above) sets Dio2 as RF switch control, which is not true here, so set it back to false.
if (res == RADIOLIB_ERR_NONE) { if (res == RADIOLIB_ERR_NONE) {
LOG_DEBUG("SX126X_TXEN pin defined. Setting RF Switch: RXEN=%i, TXEN=%i\n", SX126X_RXEN, SX126X_TXEN); res = lora.setDio2AsRfSwitch(dio2AsRfSwitch);
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 // 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
// E22 control RX and TX via DIO2. In this configuration, the E22's TXEN and DIO2 pins are connected to each other, // no effect
// but not to the MCU. #if ARCH_PORTDUINO
// 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) { 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 " LOG_DEBUG("Using MCU pin %i as RXEN and pin %i as TXEN to control RF switching\n", settingsMap[rxen], settingsMap[txen]);
"lora.setRfSwitchPins."); lora.setRfSwitchPins(settingsMap[rxen], settingsMap[txen]);
}
#else
#ifndef SX126X_RXEN
#define SX126X_RXEN RADIOLIB_NC
LOG_DEBUG("SX126X_RXEN not defined, defaulting to RADIOLIB_NC\n");
#endif
#ifndef SX126X_TXEN
#define SX126X_TXEN RADIOLIB_NC
LOG_DEBUG("SX126X_TXEN not defined, defaulting to RADIOLIB_NC\n");
#endif
if (res == RADIOLIB_ERR_NONE) {
LOG_DEBUG("Using MCU pin %i as RXEN and pin %i as TXEN to control RF switching\n", SX126X_RXEN, SX126X_TXEN);
lora.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN); lora.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
} }
#endif #endif
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 +180,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 +258,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 +288,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 +319,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
+53 -15
View File
@@ -3,6 +3,10 @@
#include "error.h" #include "error.h"
#include "mesh/NodeDB.h" #include "mesh/NodeDB.h"
#if ARCH_PORTDUINO
#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
#ifndef SX128X_MAX_POWER #ifndef SX128X_MAX_POWER
#define SX128X_MAX_POWER 13 #define SX128X_MAX_POWER 13
@@ -22,8 +26,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
@@ -31,20 +35,28 @@ template <typename T> bool SX128xInterface<T>::init()
digitalWrite(RF95_FAN_EN, 1); digitalWrite(RF95_FAN_EN, 1);
#endif #endif
#if ARCH_PORTDUINO
if (settingsMap[rxen] != RADIOLIB_NC) {
pinMode(settingsMap[rxen], OUTPUT);
digitalWrite(settingsMap[rxen], LOW); // Set low before becoming an output
}
if (settingsMap[txen] != RADIOLIB_NC) {
pinMode(settingsMap[txen], OUTPUT);
digitalWrite(settingsMap[txen], LOW); // Set low before becoming an output
}
#else
#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 #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;
@@ -78,6 +90,10 @@ template <typename T> bool SX128xInterface<T>::init()
if (res == RADIOLIB_ERR_NONE) { if (res == RADIOLIB_ERR_NONE) {
lora.setRfSwitchPins(SX128X_RXEN, SX128X_TXEN); lora.setRfSwitchPins(SX128X_RXEN, SX128X_TXEN);
} }
#elif ARCH_PORTDUINO
if (res == RADIOLIB_ERR_NONE && settingsMap[rxen] != RADIOLIB_NC && settingsMap[txen] != RADIOLIB_NC) {
lora.setRfSwitchPins(settingsMap[rxen], settingsMap[txen]);
}
#endif #endif
if (res == RADIOLIB_ERR_NONE) if (res == RADIOLIB_ERR_NONE)
@@ -109,11 +125,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);
@@ -156,14 +167,21 @@ template <typename T> void SX128xInterface<T>::setStandby()
} }
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
#if ARCH_PORTDUINO
if (settingsMap[rxen] != RADIOLIB_NC) {
digitalWrite(settingsMap[rxen], LOW);
}
if (settingsMap[txen] != RADIOLIB_NC) {
digitalWrite(settingsMap[txen], LOW);
}
#else
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power
digitalWrite(SX128X_RXEN, LOW); digitalWrite(SX128X_RXEN, LOW);
#endif #endif
#if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC) #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
digitalWrite(SX128X_TXEN, LOW); digitalWrite(SX128X_TXEN, LOW);
#endif #endif
#endif
isReceiving = false; // If we were receiving, not any more isReceiving = false; // If we were receiving, not any more
activeReceiveStart = 0; activeReceiveStart = 0;
disableInterrupt(); disableInterrupt();
@@ -184,11 +202,21 @@ template <typename T> void SX128xInterface<T>::addReceiveMetadata(meshtastic_Mes
*/ */
template <typename T> void SX128xInterface<T>::configHardwareForSend() template <typename T> void SX128xInterface<T>::configHardwareForSend()
{ {
#if ARCH_PORTDUINO
if (settingsMap[txen] != RADIOLIB_NC) {
digitalWrite(settingsMap[txen], HIGH);
}
if (settingsMap[rxen] != RADIOLIB_NC) {
digitalWrite(settingsMap[rxen], LOW);
}
#else
#if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on TX power / off RX power #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on TX power / off RX power
digitalWrite(SX128X_TXEN, HIGH); digitalWrite(SX128X_TXEN, HIGH);
#endif #endif
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC)
digitalWrite(SX128X_RXEN, LOW); digitalWrite(SX128X_RXEN, LOW);
#endif
#endif #endif
RadioLibInterface::configHardwareForSend(); RadioLibInterface::configHardwareForSend();
@@ -205,16 +233,26 @@ template <typename T> void SX128xInterface<T>::startReceive()
setStandby(); setStandby();
#if ARCH_PORTDUINO
if (settingsMap[rxen] != RADIOLIB_NC) {
digitalWrite(settingsMap[rxen], HIGH);
}
if (settingsMap[txen] != RADIOLIB_NC) {
digitalWrite(settingsMap[txen], LOW);
}
#else
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on RX power / off TX power #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on RX power / off TX power
digitalWrite(SX128X_RXEN, HIGH); digitalWrite(SX128X_RXEN, HIGH);
#endif #endif
#if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC) #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
digitalWrite(SX128X_TXEN, LOW); digitalWrite(SX128X_TXEN, LOW);
#endif
#endif #endif
// We use the PREAMBLE_DETECTED and HEADER_VALID IRQ flag to detect whether we are actively receiving // We use the PREAMBLE_DETECTED and HEADER_VALID IRQ flag to detect whether we are actively receiving
int err = lora.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT | int err = lora.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT |
RADIOLIB_SX128X_IRQ_RADIOLIB_PREAMBLE_DETECTED | RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED |
RADIOLIB_SX128X_IRQ_HEADER_VALID); RADIOLIB_SX128X_IRQ_HEADER_VALID);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
@@ -246,7 +284,7 @@ template <typename T> bool SX128xInterface<T>::isChannelActive()
template <typename T> bool SX128xInterface<T>::isActivelyReceiving() template <typename T> bool SX128xInterface<T>::isActivelyReceiving()
{ {
uint16_t irq = lora.getIrqStatus(); uint16_t irq = lora.getIrqStatus();
bool detected = (irq & (RADIOLIB_SX128X_IRQ_HEADER_VALID | RADIOLIB_SX128X_IRQ_RADIOLIB_PREAMBLE_DETECTED)); bool detected = (irq & (RADIOLIB_SX128X_IRQ_HEADER_VALID | RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED));
// Handle false detections // Handle false detections
if (detected) { if (detected) {
+55
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;
}
+9 -50
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;
}
+4
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) {
+5 -1
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

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