Compare commits

...

179 Commits

Author SHA1 Message Date
Ben Meadors
191a69dd26 Don't create potential NodeInfo storm on telemetry reponse from Repeater (#2673)
* Don't create potential NodeInfo storm on telemetry reponse from Repeaters

* Check decoded
2023-08-01 18:24:40 -05:00
Ben Meadors
9eeec6c083 Reply to Repeater in DeviceTelemetry module (#2661) 2023-08-01 16:18:10 -05:00
github-actions[bot]
b799b7bf62 [create-pull-request] automated change (#2672)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-07-31 18:51:15 -05:00
Jonathan Bennett
939a359e7e Adds DOP fields to JSON MQTT output (#2671)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-07-31 15:19:36 -05:00
GUVWAF
5a5af4707c SerialModule SIMPLE mode: use write() instead of printf() 2023-07-31 22:18:42 +02:00
Thomas Göttgens
ef5e21d3da Enable Trunk on Windows 2023-07-31 21:37:55 +02:00
Ben Meadors
8a49221b7f Update version.properties 2023-07-30 20:17:57 -05:00
Ben Meadors
76dc805184 Add Nano-g2-ultra 2023-07-30 14:07:17 -05:00
Ben Meadors
97d7a89644 Update protobufs 2023-07-30 07:58:11 -05:00
Manuel
502a6596a3 T deck: support keyboard, trackball and touchscreen (#2665)
* add hwid for auto-detection

* fix: heltec-wireless-tracker USB serial

* T-Deck support

* trunk fmt

* set FRAMERATE to 1

* fix some defines

* trunk fmt

* corrected vendor link

* T-Deck: support keyboard, trackball & touch screen

* T-Watch add touchscreen defs, remove getTouch

* fix warnings

* getTouch uint16 -> int16

* fix touch x,y

* fix I2C port

* CannedMsgModule: use entire display height

* trunk fmt

* fix I2C issue for T-Watch

* allow dest selection in canned mode

* fix: allow dest selection in canned mode

* use tft.setBrightness() to poweroff display

* Increased t-watch framerate and added back haptic feedback

* add da ref

* Move to touched

* improved sensitivity and accuracy of touch events

* use double tap to send canned message

* fix warning

* trunk fmt

* Remove extra hapticFeedback()

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-07-30 07:51:26 -05:00
Neil Hao
b9c9f0f865 nano-g2-ultra (#2660)
* 'nano-g2-ultra'

* revert overcommit

* nano-g2-ultra-fmt

* revert overcommit

* revert overcommit

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-07-29 07:54:56 -05:00
GUVWAF
ffcc1a0275 RP2040: Enable ExternalNotification and RangeTest Module, set randomSeed (#2664)
* Enable ExternalNotification (and RangeTest) Module

* Set a random seed at boot
2023-07-29 07:19:58 -05:00
Ben Meadors
3d697f8cf4 Enable SX126X RX Boosted gain by default (#2663) 2023-07-28 10:39:40 -05:00
Ben Meadors
6bd870c454 I guess we have to use SHAs (lame) 2023-07-27 07:59:39 -05:00
Ben Meadors
c782380373 Fix semgrep errors 2023-07-27 07:04:00 -05:00
Ben Meadors
0b509c7e79 Remove concurrency groups for now. They seem to cause CI hangs 2023-07-27 06:41:39 -05:00
Ben Lipsey
86af578df9 Preferred units when distance unknown (#2652)
* units when distance unknown

* replace deleted comment
2023-07-26 18:06:31 -05:00
Ben Meadors
bdcf17a3f7 Add T-Deck to S3 ota logical branch (#2644)
* Add T-Deck to S3 ota logical branch

* Revert "Add T-Deck to S3 ota logical branch"

This reverts commit d0aef9dc26.

* Add targets

* Get the bat file too
2023-07-25 16:13:32 -05:00
github-actions[bot]
81edf363d7 [create-pull-request] automated change (#2645)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-07-25 05:46:11 -05:00
Ben Meadors
96c6a20e03 Ensure that MQTT is enabled and log initialization (#2643) 2023-07-24 12:33:01 -05:00
Ben Meadors
3fbe2d771c Hopefully this cancels previous CI runs for a branch (#2642) 2023-07-24 09:47:16 -05:00
Jonathan Bennett
ac9c81f6d1 Check Position Request for Primary Channel (#2638)
Prevents leaking location data to secondary channels.

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-07-24 09:37:56 -05:00
Ben Meadors
490abdac96 Whoops 2023-07-24 07:22:04 -05:00
Ben Meadors
b17436a023 Patch gather-artifacts 2023-07-24 06:54:05 -05:00
rcarteraz
b9ae63cb3c Update Bug Report.yml (#2640)
Add T-Deck, T-Watch, Wireless Paper, and Wireless Tacker to device list.
2023-07-24 06:44:19 -05:00
github-actions[bot]
55701692fd [create-pull-request] automated change (#2637)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-07-24 06:43:47 -05:00
Ben Meadors
470363d294 Update Hydra to use new TXEN->DIO2 macro (#2636) 2023-07-22 18:59:33 -05:00
github-actions[bot]
fb21bfe0f5 [create-pull-request] automated change (#2635)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-07-22 09:37:51 -05:00
Ben Meadors
0739bc0cea T-Watch S3 Support (#2632)
* T-Watch WIP

* Updates

* Temp

* Update screen spi bus and and backlight en

* Peripherals progress

* Fixes

* Fixes

* Updates

* DRV scaffolding

* Fixed touch-screen driver selection. WIP on DRV haptic feedback

* DRV2605 pmu channel

* Trunk

* Fixes and defaults

* Dropped an s

* Move PMU and turn off screen that way

* Add t-deck and t-watch-s3 to CI and cleanup

* More cleanup
2023-07-22 09:26:54 -05:00
andrew-moroz
1c74479555 xiao-ble: add initial support for the Xiao BLE + Ebyte E22-900M30S (#2633)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-07-21 20:37:00 -05:00
rcarteraz
084ad1b722 Update main_matrix.yml (#2634)
Add Heltec Wireless Paper to S3 Boards
2023-07-21 19:32:39 -05:00
Manuel
2486892e6d Basic T-Deck support (#2630)
* add hwid for auto-detection

* fix: heltec-wireless-tracker USB serial

* T-Deck support

* trunk fmt

* set FRAMERATE to 1

* fix some defines

* trunk fmt

* corrected vendor link
2023-07-19 08:13:51 -05:00
github-actions[bot]
77efbb3f5d [create-pull-request] automated change (#2626)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-07-18 10:00:12 -05:00
Ben Meadors
eb7025f1b1 Add Hydra specific target to define GPS EN pin and limit tx power (#2608)
* Use DIO2 bridged to TXEN and remove TX/RXEN pin switching altogether

* Add Hydra specific target to limit tx power and define GPS EN

* Whoops
2023-07-18 07:09:55 -05:00
github-actions[bot]
69beef8310 [create-pull-request] automated change (#2625)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-07-18 06:19:37 -05:00
Manuel
468807466c fix BLE PIN screen for not so large screens (#2624)
* add hwid for auto-detection

* fix: heltec-wireless-tracker USB serial

* fix BLE PIN screen for not so large displays
2023-07-18 06:10:39 -05:00
code8buster
8927cffd64 GPS log modifications (#2609)
* Move module info for use in functions outside of probe, refmt MON-VER message

* use checksum function in probe message

* Housekeeping on some comments, unsign the position ctr again
2023-07-17 20:27:14 -05:00
tropho23
5995c7060d Added triple-press GPS toggle button changes for select ESP32 devices (#2617)
* Added triple-press GPS toggle button changes

* Revert edits to extensions.json

* comma'd

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: code8buster <communismisgreat@national.shitposting.agency>
2023-07-17 18:55:40 -05:00
Manuel
541291cc70 resolve heltec-wireless-tracker serial issue (#2621)
* add hwid for auto-detection

* fix: heltec-wireless-tracker USB serial
2023-07-17 13:06:34 -05:00
Mark Trevor Birss
4306c32349 Update variant.h (#2620)
Update M5Stack CoreInk enable GPS/BDS

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-07-17 09:20:42 -05:00
Manuel
491fe52841 add hwid for auto-detection (#2619) 2023-07-17 09:20:05 -05:00
Manuel
ad5de5a724 increase BT NIMBLE task stack size by 1k (#2618) 2023-07-17 06:23:27 -05:00
Manuel
ab32503601 Heltec-Tracker: GPS support (#2615)
* Heltec-Tracker: GPS support

* trunk fmt

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-07-16 16:57:14 -05:00
Ben Meadors
e4e26a819b Check if hasSensor an run if not initialized (#2613) 2023-07-16 15:23:31 -05:00
Ben Meadors
6d97d5dfa2 Bump PR artifacts github action 2023-07-16 15:18:42 -05:00
Manuel
c75965480f Heltec-Tracker: TFT LCD support (#2612)
* Heltec-Tracker: TFT LCD support

* trunk fmt

* backwards compatibility  with ST7735 devices

* trunk fmt
2023-07-15 08:53:26 -05:00
luzpaz
003047baaf Fix various typos (#2607)
* Fix various typos

Found via `codespell -q 3 -L acount,clen,dout`

* Trunk reformatting

---------

Co-authored-by: code8buster <communismisgreat@national.shitposting.agency>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-07-14 16:25:20 -05:00
Ben Meadors
4ace59fc18 Partial Heltec Wireless Paper and Wireless Tracker support (#2594)
* WIP

* Comment

* WIP

* TFT_CTRL

* Update platformio.ini

update to current latest version available

* Update EInkDisplay2.cpp

Is the e-ink Display a DEPG0213BN ?

* Logging

* trunk fmt

---------

Co-authored-by: Mark Trevor Birss <markbirss@gmail.com>
2023-07-14 16:12:30 -05:00
Dmitry Galenko
aa0b56e947 GPS: Implement Power Management, Refactor Code and Fix GSA Message Configuration for U-Blox hardware (#2606) 2023-07-12 19:35:41 -05:00
Ben Lipsey
42d79d012e center text based on screen width (#2603) 2023-07-09 20:16:36 -05:00
Ben Meadors
d3e7e45ded Append alpha to release name 2023-07-09 06:17:17 -05:00
github-actions[bot]
0cca7751cd [create-pull-request] automated change (#2600)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-07-09 06:15:48 -05:00
Ben Meadors
de53280ffc PIN_GPS_EN power toggling (#2592)
* PIN_GPS_EN

* Remove extra digitalWrite

* GPS_POWER_TOGGLE macro enabled. Added WSLv3 too

* Update variant.h

* Update variant.h

* Fixed macro guard
2023-07-08 21:01:00 -05:00
Ben Meadors
65aafe7ea1 Update protos 2023-07-08 20:46:34 -05:00
Ben Meadors
6e96216ba3 MQTT client proxying (#2587)
* WIP on MQTT proxy message queue

* Fix copy paste goof

* Progress on uplink

* Has packets

* Avoid trying to connect if we're proxying

* Pointer correctly

* Remove wifi guards

* Client proxy subscribe

* Fixed method that got bababababorked somehow... personally I blame CoPilot

* Short circuit logic

* Remove canned settings

* Missed some stuff in the move

* Guard pubsub client for non-networked variants

* Has networking guard

* else

* Return statement for fall-thru

* More gaurd removals

* Removed source filters. No wonder I was confused

* Bounding

* Scope guard around else and fix return

* Portduino

* Defs instead

* Move macro up to actually fix portduino

* Size_t

* Unsigned int

* Thread interval

* Protos

* Protobufs ref
2023-07-08 20:37:04 -05:00
Max-Plastix
da389eb787 Correct unused variable warning and typo around GNSS_MODEL_UNKNOWN (#2596)
* Small warning and typo cleanup.

* Update GPS.cpp (missed one instance of GNSS_MODEL_UNKONW)
2023-07-08 18:30:52 -05:00
GUVWAF
d8ad2b3f48 RPi Pico screen, CannedMessageModule (CardKB) and reboot support (#2595)
* Make input_source case insensitive

* Implement reboot for RP2040

* Remove EXT_NOTFIFY_OUT as it conflicts with I2C and module is not supported

* RP2040 has screen, button and wire

* Add default I2C pins also for Pico W
2023-07-08 11:32:36 -05:00
Ben Meadors
97606cd382 New platform updates (#2593) 2023-07-07 18:58:49 -05:00
prokrypt
5c34e36bec Temporary band-aid to address mesh [un]reliability after queue "fix" (#2588) 2023-07-06 06:43:21 -05:00
Dmitry Galenko
9c141919f6 Initial support for MonteOps's fixed hardware platform (#2582)
* Initial support for MonteOps's fixed hardware platform

* Update platformio env config + cleanup

* Fix platformio build

* Fix platformio build

* Fix wrong definition logic for NCP5623

* Fix another wrong definition logic for NCP5623, it's not board feature

* Fix wrong definition logic for NCP5623 in External Notification code, it's not board feature

* We need for CI magic here

* Another fix related to NCP5623

* Fix cosmetic issue with redifined variable

* Fix typo

* Cleanup and update defs for HW1

* Fix OEM RAK4631

* Fix AQ sensor reading

* Fix AQ sensor reading (better variant)

* Fix build for other nRF52 devices

* Replace HAS_EINK_RAK to RAK_4631
2023-07-03 09:34:32 -05:00
GUVWAF
b9ad274104 Update retransmission timer based on client offset (#2583) 2023-07-02 16:30:28 -05:00
Dmitry Galenko
4ef61f0f15 GPS: Performance improvment for U-Blox hardware (#2574)
* Add proper configuration procedure for U-Blox modules

* More human friendly getACK

* Fix checksum calculation and payload

* GPS: move unsigned int check

* Introduce UBX protocol payload checksuming

* Fix missed checksums calculation for UBX-CFG-CFG
2023-07-01 19:20:40 -05:00
github-actions[bot]
c120549215 [create-pull-request] automated change (#2580)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-06-27 20:29:11 -05:00
github-actions[bot]
7ca2e818df [create-pull-request] automated change (#2579)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-06-27 19:38:45 -05:00
Thomas Göttgens
f02923435b Fix build warning 2023-06-27 23:10:53 +02:00
Ben Meadors
eb0a96a79e Default ext. notification output for RAK to LED #2 (#2570)
* Default ext. notification output for RAK to LED #2

* Enabled by default

* Update

* Wrong macro

* Output and nag
2023-06-27 12:21:06 -05:00
Ben Meadors
9e2b86b92c Bump RadioLib to 6.1.0 (#2577)
* Bump RadioLib to 6.1.0

* RP2040

* More excludes

* Jan added a lot of stuff apparently

* Stay back a version on portduino for now

* It wasn't this. I need to remove the docker build from ci
2023-06-27 07:08:32 -05:00
Ben Meadors
d0cf70c8b3 Remove docker steps from PR build process 2023-06-27 06:59:28 -05:00
charminULTRA
44a906dd01 RAK14001 LED - Turn on to 50% at boot (#2571)
* Addition of RAK 14001 functionality to start and stay on for boot

* Fixing via Trunk

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-06-26 19:59:44 -05:00
GUVWAF
ccb682bbb8 Call getMacAddr within pickNewNodeNum() (#2576)
It could be called from within NodeDB::init() before it is set
2023-06-26 19:26:12 -05:00
Ben Meadors
e677a02273 Map built-in LED on RAK-11310 (#2568) 2023-06-21 12:11:42 -05:00
GUVWAF
47168d5063 Always assign NodeNum based on MAC address (#2567)
* Always assign NodeNum based on MAC address
Step one of trying to fix infinite loop

* Store our mac.addr again to ignore an already existing NodeNum if it's us
2023-06-20 16:29:25 -05:00
github-actions[bot]
5591b9b9f5 [create-pull-request] automated change (#2564)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-06-18 20:46:06 -05:00
Ben Meadors
a2c5b92840 NodeDB Lite migration (#2554)
* Skadoosh

* Removing deprecated fields

* Remove remaining deprecations

* Macro

* Macro

* WIP conversion

* Lots of type conversions between Lite versions and new NodeDB methods

* Trunk

* Conversion

* NULL

* Init

* Rename

* Position

* Reworked conversion to NodeInfo for PhoneAPI
2023-06-17 09:10:09 -05:00
GUVWAF
685d27f566 Update core to 3.2.2 and use real FreeRTOS defs (#2558)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-06-13 05:44:24 -05:00
Ben Meadors
f71869215d Set pin for RAK-12039 to allow I2C auto-detect (#2555)
* SET pin for RAK-12039 and put back macaddr for now

* Guard against epaper RAK variant

* Update main.cpp

* Add these back
2023-06-09 05:58:58 -05:00
Ben Meadors
81f80546b4 Remove deprecated MyNodeInfo fields (#2552)
* Skadoosh

* Removing deprecated fields

* Remove remaining deprecations

* Macro

* Macro
2023-06-08 08:07:32 -05:00
Ben Meadors
44a54278b3 Skadoosh (#2549) 2023-06-07 12:59:01 -05:00
Michel Jung
194833d77f Fix static ethernet config (#2544)
With static ethernet config, `status` stayed `0` which let the function return
without setting `ethEvent`. Therefore, `reconnectETH` was never called and network services were never started.

Also, the RAK4631 uses little endian, which is why the IP addresses need to be
converted before setting them.

Fixes #2543
2023-06-06 19:26:13 -05:00
Andre K
207d421fca refactor tx delay calculation for routers and non-routers (#2542) 2023-06-06 17:33:51 -05:00
rcarteraz
fb14487f2f Update pull_request_template.md (#2547)
Swap clang-format with trunk check
2023-06-06 17:31:27 -05:00
GUVWAF
365a91f3d9 Add Raspberry Pi Pico and RAK11310 to bug report 2023-06-06 21:40:44 +02:00
github-actions[bot]
5edc872c31 [create-pull-request] automated change (#2540)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-06-03 06:19:38 -05:00
Ben Meadors
cd787232ca Use INA for device battery level (#2536)
* WIP

* Continued wip

* We got em

* Voltage sensor base class

* INA voltage

* Log it

* Stacie's mom has got it going on

* Move declaration up

* Last one

* Sneaky little bugger

* Macro guard to avoid calling methods
2023-06-02 06:32:34 -05:00
GUVWAF
344baf7ffc Cancel rebroadcast in Tx queue upon receiving another rebroadcast (#2538)
* Make portduino great again

* Upon receiving packet that was seen recently, cancel a rebroadcast if there was one in Tx queue already

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-06-01 13:36:30 -05:00
Ben Meadors
a491ceefcd Wio-e5 wip (#2265)
* Wio-e5 / STM32WL wip

* Stubbing some FS stuff out

* Wio-e5 / STM32WL wip

* Stubbing some FS stuff out

* Wio-e5 / STM32WL wip

* Stubbing some FS stuff out

* Wio-e5 / STM32WL wip

* Stubbing some FS stuff out

* LittleFS compiles. Can't check with actual device.

* make cppcheck happy again

* Guard against accelerometer thread

* Missed a spot

* Upload via ST-LINK

* Derive MAC address from UID

* upload port

* Trunk it

* Guard it

* Maybe fix the cache error on startup.

* Latest RadioLib ref to fix SubGHZ

* revert nasty Sub-GHz Hack

* Boots and radio inits with RadioLib 6.0, LittleFS doesn't seem to work

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: GUVWAF <thijs@havinga.eu>
2023-06-01 07:14:55 -05:00
github-actions[bot]
1524c2365f [create-pull-request] automated change (#2537)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-06-01 06:02:23 -05:00
Ben Meadors
9d3dc9283c Enable range test module (sending only) on NRF (#2534)
* Enable range test module (sending only) on NRF

* Consolidate
2023-05-31 20:08:32 -05:00
Ben Meadors
b1398d0770 Open up Serial Module to T-Echo (#2533)
* Remove macro guards for T-Echo

* Missed a spot

* Gaurd serial2

* Didn't mean to circumcize that declaration
2023-05-31 05:30:59 -05:00
github-actions[bot]
110ec85137 [create-pull-request] automated change (#2532)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-05-30 07:36:36 -05:00
code8buster
99a31c1fad Make sure the mosfet gate for adc measuring circuit is low (#2530)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-05-30 06:15:19 -05:00
Ben Meadors
113026c372 Allow overriding the default Serial console output settings (#2528)
* Implement override_console_serial_port

* It's opposite day in Logictown

* Try to use native serial types for platforms

* Fix for s3

* Trunk

* Screw it... just declare as Print and handle init

* Alright, chatty kathy

* Missed a spot

* I'll take "Kill that FIXME" for 800, Alex

* Badunkadunk

* Refactor out a lot of duplicated code

* Boogers

* Okay I probably should stop changing everything
2023-05-30 05:26:34 -05:00
Thomas Göttgens
3bc82e59dc Merge pull request #2531 from lewisxhe/master
Fix fetchI2CBus judgment error
2023-05-30 09:51:54 +02:00
lewishe
24bb52e83f Fix fetchI2CBus judgment error 2023-05-30 11:22:29 +08:00
Lewis He
68ef27df8b Merge branch 'meshtastic:master' into master 2023-05-29 09:07:06 +08:00
Ben Meadors
9ddbfc0e3e CalTopo NMEA mode (#2526)
* CalTopo NMEA mode

* Didn't need that actually

* Missed a paren
2023-05-28 14:56:44 -05:00
GUVWAF
e699427bfc RP2040: Enable telemetry and update HW models (#2525) 2023-05-28 10:30:54 -05:00
Ben Meadors
696afeef41 Protos 2023-05-28 09:44:47 -05:00
GUVWAF
35ee12cb4c RP2040: Use Pico SDK USB stack instead of TinyUSB (#2523)
Seems to fix freeze, serial output still stops after a while
2023-05-27 19:22:26 -05:00
GUVWAF
94f5c04e19 Update lastSentToPhone after sendTelemetry (#2522) 2023-05-27 12:35:45 -05:00
Thomas Göttgens
fbcd6743fd trunk fmt 2023-05-27 10:29:01 +02:00
lewishe
1b35cc018f Fix t-beam-s3-core display not working 2023-05-27 10:29:01 +02:00
thebentern
f18b8328a2 [create-pull-request] automated change 2023-05-27 10:28:08 +02:00
Thomas Göttgens
d241a010aa trunk fmt 2023-05-27 10:03:02 +02:00
lewishe
78af6e2ed8 Fix t-beam-s3-core display not working 2023-05-27 10:17:37 +08:00
code8buster
7475c8647c 2.5dB could be a more appropriate attenuation for heltec ADCs (#2511)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-05-26 06:16:40 -05:00
GUVWAF
f3af3c1c33 RP2040: Reverse dmac assignment
src.id[0] and src.id[1] that are used for Bluetooth name seem not unique
2023-05-25 15:56:57 +02:00
Thomas Göttgens
a583163766 fix BSEC2 BME680 Sensor Readings 2023-05-25 15:56:39 +02:00
Ben Meadors
e943fc6b8a Remove RP2040 check until we can make it behave 2023-05-25 06:48:35 -05:00
Ben Meadors
f2cf0ed315 Platform packages version (#2515)
* I think something is wrong here

* Use tag on repo
2023-05-24 14:09:37 -05:00
Thomas Göttgens
59b1adf12f Move to our own logging system (#2513) 2023-05-24 10:29:50 -05:00
Thomas Göttgens
1ae77d198d fix onebutton deprection warning (#2512) 2023-05-24 07:16:05 -05:00
Ben Meadors
2728e86aab No longer are you extras, my friends 2023-05-24 07:08:22 -05:00
Ben Meadors
f8cba0e7f2 Remove pegged commit hash since 3.2.1 is released 2023-05-24 07:04:07 -05:00
Thomas Göttgens
e5b049d2e2 trunk 2023-05-24 02:48:48 +02:00
Thomas Göttgens
52df85c338 tryfix cppcheck errors
also ignore temporary files
2023-05-24 02:44:30 +02:00
Thomas Göttgens
1dfa8f2d9e RAK11310 (#2299)
* POC. Board definition JSON upcoming. Generic for now

* side-effect: RP2040 is building again.

* WIP Pico Targets

* current state of affairs

* ahem

* POC. Board definition JSON upcoming. Generic for now

* side-effect: RP2040 is building again.

* WIP Pico Targets

* current state of affairs

* ahem

* fmt

* update toolkit and fmt

* Add built in LED pin

* Use arduino pins

* init SPI bus on right pins.

* Use SPI1 and control chip select manually

* Use macro define for SPI selection. This needs to be defined in the ini file since portduino needs it inside the framework source

* Remove manual CS; works when not using setCS()

* Remove whoopsie debug line

* we are not ARDUINO_AVR_NANO_EVERY any more

* fix rp2040 compilation

* fix RadioLibHAL

* Use new arduino-pico core

* Use cortex-m0plus for BSEC2 library

* Forgot RAK11310 target for BSEC2 library

* That branch was merged

* RAK11310 is working too

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: GUVWAF <thijs@havinga.eu>
2023-05-23 16:19:36 -05:00
Ben Meadors
4f0922ec2b Concat remote hardware pins (#2508) 2023-05-23 16:18:14 -05:00
github-actions[bot]
eb916da8ce [create-pull-request] automated change (#2506)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-05-22 20:19:13 -05:00
Ben Meadors
1b68408f2f Remote hardware overhaul (#2495)
* Update protos

* WIP

* Param

* Has remote hardware

* Protos

* Initializer

* Added new admin message for node remote hardware pins

* Badunkatrunk

* Init and memcpy
2023-05-22 07:00:20 -05:00
code8buster
a9fed83d9a Make pull request targets happy 2023-05-16 21:46:55 +02:00
code8buster
c0979e29ff Fix a few platformio envs, maybe make cppcheck happy 2023-05-16 21:46:55 +02:00
code8buster
9878ff3836 Tryfix datatype errors 2023-05-16 21:46:55 +02:00
code8buster
3219ad33ef Add ADC channels to esp variants, plug code back in to make sure other archs work 2023-05-16 21:46:55 +02:00
code8buster
6113a1fb70 Tryfix heltec v2 adc issues being on SAR2 2023-05-16 21:46:55 +02:00
code8buster
d11bcda292 Implementing a calibrated ESP32 ADC reading 2023-05-16 21:46:55 +02:00
IhorNehrutsa
508cdf6060 Up OneButton library version to 2.1.0 (#2480)
* Up OneButton library version to 2.1.0

* Update ButtonThread.h

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-05-16 07:01:42 -05:00
Thomas Göttgens
0009b98996 Merge pull request #2492 from meshtastic/bug-2490
fixes #2490 - hard coded 8 hour limit
2023-05-15 18:04:17 +02:00
Thomas Göttgens
77dace1043 derp 2023-05-15 17:16:32 +02:00
Thomas Göttgens
e02720b29b fixes #2490 - hard coded 8 hour limit 2023-05-15 17:16:32 +02:00
Thomas Göttgens
ffa85ebccd Merge pull request #2491 from meshtastic/mqtt-update
add optional GPS fields to JSON
2023-05-15 17:16:06 +02:00
Thomas Göttgens
f9b2556cd4 add optional GPS fields to JSON 2023-05-15 15:40:22 +02:00
IhorNehrutsa
9c683f4c87 Fix LOG_DEBUG messages when no DEBUG_PORT. (#2485)
* Fix LOG_DEBUG messages when no DEBUG_PORT.

* Fix LOG_DEBUG messages when no DEBUG_PORT.

* Fix LOG_DEBUG messages when no DEBUG_PORT.

* Fix LOG_DEBUG messages when no DEBUG_PORT.
2023-05-13 05:33:14 -05:00
github-actions[bot]
cf07d2dbcd [create-pull-request] automated change (#2488)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-05-12 20:48:26 -05:00
Ben Meadors
7711b03bd8 Update nrf and esp32 platform versions (#2486) 2023-05-12 08:38:53 -05:00
Ben Meadors
c52fddac53 Adding device.is_managed protobuf (#2487) 2023-05-12 08:38:30 -05:00
Thomas Göttgens
b0c3816a8b Merge pull request #2484 from meshtastic/fix-hydra-rf-switch
Fix hydra rf switch
2023-05-12 10:53:52 +02:00
Ben Meadors
6cdf2817f4 Put this back in place 2023-05-11 20:09:34 -05:00
Ben Meadors
f7e1f4cea6 Fix hydra (for real this time) 2023-05-11 19:56:55 -05:00
Ben Meadors
75504793e8 Skip setting dio2 as rf switch altogether if txen is defined 2023-05-11 06:52:27 -05:00
Ben Meadors
4029f731c9 Merge remote-tracking branch 'origin' into fix-hydra-rf-switch 2023-05-10 08:41:35 -05:00
Thomas Göttgens
666a1f3401 Merge pull request #2467 from meshtastic/BSEC2
use BSEC2
2023-05-10 14:57:21 +02:00
Thomas Göttgens
70dc13a998 use BSEC2 only 2023-05-10 14:14:48 +02:00
Thomas Göttgens
9841d49fb8 Merge branch 'master' into BSEC2 2023-05-10 13:31:46 +02:00
Thomas Göttgens
28ec4e35ec Merge pull request #2476 from meshtastic/Radiolib-6
update portduino to radiolib6
2023-05-10 11:09:43 +02:00
Thomas Göttgens
55cef30f93 update portduino to radiolib6 2023-05-10 11:02:32 +02:00
rcarteraz
0e15d6a5c2 Update Heltec WSL variant.h to add I2C definitions. (#2475) 2023-05-09 19:30:43 -05:00
Thomas Göttgens
29199e4732 New naming scheme 2023-05-08 20:33:34 +02:00
Thomas Göttgens
6fc061fa43 Merge pull request #2472 from meshtastic/Radiolib-6
Platformio 6.1.7 udate
2023-05-08 20:31:51 +02:00
Thomas Göttgens
c14b075996 Merge branch 'master' into Radiolib-6 2023-05-08 20:31:20 +02:00
Thomas Göttgens
6963e43e9f Platformio 6.1.7 doesn't like dots in env names any more. 2023-05-08 20:28:11 +02:00
Thomas Göttgens
1d90096cba rearrange pio build system dependencies
also update trunk
2023-05-08 14:40:10 +02:00
Thomas Göttgens
c1a1b450e3 RadioLib6 support 2023-05-08 14:40:10 +02:00
Thomas Göttgens
f7041994af rearrange pio build system dependencies
also update trunk
2023-05-08 14:03:03 +02:00
Thomas Göttgens
5037a50059 RadioLib6 support 2023-05-08 13:18:28 +02:00
Mark Trevor Birss
2e915e782b Delete bpi_picow_esp32_s3.json 2023-05-08 10:31:12 +02:00
Mark Trevor Birss
e761631d5e Add files via upload 2023-05-08 10:31:12 +02:00
github-actions[bot]
19a310e196 [create-pull-request] automated change (#2469)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-05-06 19:37:01 -05:00
Thomas Göttgens
5ec624d9c3 Merge pull request #2462 from meshtastic/bug-2451
probably fixes #2451 - please test
2023-05-06 23:37:35 +02:00
Thomas Göttgens
b4ff37104a fix NMEA Timestamp for good 2023-05-06 23:16:39 +02:00
Thomas Göttgens
81bfd69a41 fmt 2023-05-06 18:13:52 +02:00
Thomas Göttgens
57aaf7f6ee Merge branch 'bug-2451' of github.com:meshtastic/firmware into bug-2451 2023-05-06 18:11:56 +02:00
Thomas Göttgens
9b6ac98ae0 use the device time, only use gps timestamp as a fallback. 2023-05-06 18:10:20 +02:00
Thomas Göttgens
e1c4968c58 wrong datapoint 2023-05-06 18:10:20 +02:00
Thomas Göttgens
694fd04367 probably fixes #2451 - please test 2023-05-06 18:10:20 +02:00
Thomas Göttgens
cdc8bf44e9 use the device time, only use gps timestamp as a fallback. 2023-05-06 18:10:00 +02:00
Ben Meadors
09d48f659e RAK14001 RGB LED support (#2464)
* WIP

* WIP

* Moved it

* More random strobey behavior

* Guard to RAK4630 devices for now

* Oops

* Ship it
2023-05-06 07:17:40 -05:00
Thomas Göttgens
46e29402a6 fmt 2023-05-05 18:11:44 +02:00
Thomas Göttgens
10f41e376c use BSEC2 for ESP32-C3 2023-05-05 18:09:06 +02:00
Thomas Göttgens
39aa756100 wrong datapoint 2023-05-05 14:29:14 +02:00
Thomas Göttgens
17e25babb1 probably fixes #2451 - please test 2023-05-05 14:29:14 +02:00
Manuel Verch
7c9d0a022a fix AI C3 DevKit-M configuration 2023-05-05 09:39:22 +02:00
Thomas Göttgens
313860c8a4 fix #2460 - we only really need the router object after nodedb init, so lets move it there. 2023-05-04 11:06:49 +02:00
IhorNehrutsa
e360c62480 RemoteHardwareModule.cpp: Hot Fix digitalReads() pinModes(mask, INPUT_PULLUP) (#2459) 2023-05-03 21:09:18 -05:00
IhorNehrutsa
973b30fc0b Update RemoteHardwareModule.cpp (#2454) 2023-05-03 06:25:03 -05:00
Ben Meadors
a6385a522d Disable TX/RX EN in favor of power EN over TX_EN (#2456)
* Disable TX/RX EN in favor of power EN over TX_EN

* Oops
2023-05-03 06:24:09 -05:00
Ben Meadors
6aa9e37872 Oops 2023-05-02 15:05:23 -05:00
Ben Meadors
5afa92395d Disable TX/RX EN in favor of power EN over TX_EN 2023-05-02 15:04:23 -05:00
github-actions[bot]
b6ff80f0b7 [create-pull-request] automated change (#2453)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-05-01 17:36:38 -05:00
283 changed files with 7560 additions and 1620 deletions

View File

@@ -37,13 +37,19 @@ body:
- T-Lora v1
- T-Lora v1.3
- T-Lora v2 1.6
- T-Deck
- T-Echo
- T-Watch
- Rak4631
- Rak11200
- Rak11310
- Heltec v1
- Heltec v2
- Heltec v2.1
- Heltec V3
- Heltec Wireless Paper
- Heltec Wireless Tracker
- Raspberry Pi Pico (W)
- Relay v1
- Relay v2
- DIY

View File

@@ -7,7 +7,8 @@
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
- Please do not check in files that don't have real changes
- Please do not reformat lines that you didn't have to change the code on
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor and the 'clang-format' extension,
because automatically follows our indentation rules and it's auto reformatting will not cause spurious changes to lines.
- 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),
because it automatically follows our indentation rules and its auto reformatting will not cause spurious changes to lines.
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
- If your other co-developers have comments on your PR please tweak as needed.
- Please also enable "Allow edits by maintainers".

View File

@@ -17,11 +17,11 @@ jobs:
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
with:
repo: "meshtastic/web"
file: "build.tar"
target: "build.tar"
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
@@ -40,11 +40,11 @@ jobs:
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
with:
repo: "meshtastic/firmware-ota"
file: "firmware.bin"
target: "release/bleota.bin"
repo: meshtastic/firmware-ota
file: firmware.bin
target: release/bleota.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string

View File

@@ -17,11 +17,11 @@ jobs:
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
with:
repo: "meshtastic/web"
file: "build.tar"
target: "build.tar"
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
@@ -38,11 +38,11 @@ jobs:
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
with:
repo: "meshtastic/firmware-ota"
file: "firmware-s3.bin"
target: "release/bleota-s3.bin"
repo: meshtastic/firmware-ota
file: firmware-s3.bin
target: release/bleota-s3.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string

View File

@@ -1,4 +1,7 @@
name: CI
#concurrency:
# group: ${{ github.ref }}
# cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
on:
# # Triggers the workflow on push but only for the master branch
push:
@@ -23,9 +26,9 @@ jobs:
matrix:
include:
- board: rak11200
- board: tlora-v2-1-1.6
- board: tlora-v2-1-1_6
- board: tbeam
- board: heltec-v2.1
- board: heltec-v2_1
- board: meshtastic-diy-v1
- board: rak4631
- board: t-echo
@@ -33,6 +36,9 @@ jobs:
- board: m5stack-coreink
- board: tbeam-s3-core
- board: tlora-t3s3-v1
- board: t-watch-s3
- board: t-deck
#- board: rak11310
runs-on: ubuntu-latest
steps:
@@ -43,7 +49,7 @@ jobs:
- name: Trunk Check
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: trunk-io/trunk-action@v1
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
- name: Check ${{ matrix.board }}
run: bin/check-all.sh ${{ matrix.board }}
@@ -57,14 +63,15 @@ jobs:
- board: tlora-v2
- board: tlora-v1
- board: tlora_v1_3
- board: tlora-v2-1-1.6
- board: tlora-v2-1-1.8
- board: tlora-v2-1-1_6
- board: tlora-v2-1-1_8
- board: tbeam
- board: heltec-v1
- board: heltec-v2.0
- board: heltec-v2.1
- board: tbeam0.7
- board: heltec-v2_0
- board: heltec-v2_1
- board: tbeam0_7
- board: meshtastic-diy-v1
- board: hydra
- board: meshtastic-dr-dev
- board: nano-g1
- board: station-g1
@@ -82,8 +89,12 @@ jobs:
include:
- board: heltec-v3
- board: heltec-wsl-v3
- board: heltec-wireless-tracker
- board: heltec-wireless-paper
- board: tbeam-s3-core
- board: tlora-t3s3-v1
- board: t-watch-s3
- board: t-deck
uses: ./.github/workflows/build_esp32_s3.yml
with:
board: ${{ matrix.board }}
@@ -96,23 +107,26 @@ jobs:
include:
- board: rak4631
- board: rak4631_eink
- board: monteops_hw1
- board: t-echo
- board: pca10059_diy_eink
- board: feather_diy
- board: nano-g2-ultra
uses: ./.github/workflows/build_nrf52.yml
with:
board: ${{ matrix.board }}
# build-rpi2040:
# strategy:
# fail-fast: false
# max-parallel: 2
# matrix:
# include:
# - board: pico
# uses: ./.github/workflows/build_rpi2040.yml
# with:
# board: ${{ matrix.board }}
build-rpi2040:
strategy:
fail-fast: false
max-parallel: 2
matrix:
include:
- board: pico
- board: rak11310
uses: ./.github/workflows/build_rpi2040.yml
with:
board: ${{ matrix.board }}
build-native:
runs-on: ubuntu-latest
@@ -148,12 +162,14 @@ jobs:
release/device-*.bat
- name: Docker login
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
uses: docker/login-action@v2
with:
username: meshtastic
password: ${{ secrets.DOCKER_TOKEN }}
- name: Docker setup
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
uses: docker/setup-buildx-action@v2
- name: Docker build and push tagged versions
@@ -166,7 +182,7 @@ jobs:
tags: meshtastic/device-simulator:${{ steps.version.outputs.version }}
- name: Docker build and push
if: github.ref == 'refs/heads/master'
if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
uses: docker/build-push-action@v3
with:
context: .
@@ -186,7 +202,8 @@ jobs:
gather-artifacts:
runs-on: ubuntu-latest
needs: [build-esp32, build-esp32-s3, build-nrf52, build-native] #, build-rpi2040]
needs:
[build-esp32, build-esp32-s3, build-nrf52, build-native, build-rpi2040]
steps:
- name: Checkout code
uses: actions/checkout@v3
@@ -242,8 +259,9 @@ jobs:
retention-days: 30
- name: Create request artifacts
continue-on-error: true # FIXME: Why are we getting 502, but things still work?
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
uses: gavv/pull-request-artifacts@v1.0.0
uses: gavv/pull-request-artifacts@v1.1.0
with:
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
@@ -301,7 +319,7 @@ jobs:
with:
draft: true
prerelease: true
release_name: Meshtastic Firmware ${{ steps.version.outputs.version }}
release_name: Meshtastic Firmware ${{ steps.version.outputs.version }} Alpha
tag_name: v${{ steps.version.outputs.version }}
body: |
Autogenerated by github action, developer should edit as required before publishing...

View File

@@ -14,6 +14,6 @@ jobs:
uses: actions/checkout@v3
- name: Trunk Check
uses: trunk-io/trunk-action@v1
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
with:
trunk-token: ${{ secrets.TRUNK_TOKEN }}

1
.gitignore vendored
View File

@@ -30,3 +30,4 @@ __pycache__
venv/
release/
.vscode/extensions.json
/compile_commands.json

1
.trunk/.gitignore vendored
View File

@@ -5,3 +5,4 @@
plugins
user_trunk.yaml
user.yaml
shims

View File

@@ -1,36 +1,37 @@
version: 0.1
cli:
version: 1.7.0
version: 1.9.1
plugins:
sources:
- id: trunk
ref: v0.0.14
ref: v0.0.17
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- ruff@0.0.260
- yamllint@1.30.0
- taplo@0.7.0
- ruff@0.0.265
- yamllint@1.31.0
- isort@5.12.0
- markdownlint@0.33.0
- markdownlint@0.34.0
- oxipng@8.0.0
- svgo@3.0.2
- actionlint@1.6.23
- actionlint@1.6.24
- flake8@6.0.0
- hadolint@2.12.0
- shfmt@3.5.0
- shellcheck@0.9.0
- black@23.3.0
- git-diff-check
- gitleaks@8.16.2
- gitleaks@8.16.3
- clang-format@14.0.0
- prettier@2.8.7
- prettier@2.8.8
disabled:
- taplo@0.7.0
- shellcheck@0.9.0
- shfmt@3.5.0
- oxipng@8.0.0
- actionlint@1.6.22
- markdownlint@0.33.0
- markdownlint@0.34.0
- hadolint@2.12.0
- svgo@3.0.2
runtimes:

View File

@@ -1,4 +1,5 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "trunk.io"
"editor.defaultFormatter": "trunk.io",
"trunk.enableWindows": true
}

View File

@@ -1,12 +1,15 @@
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
platform = platformio/espressif32@^6.1.0
platform = platformio/espressif32@^6.3.2
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
upload_speed = 921600
debug_init_break = tbreak setup
monitor_filters = esp32_exception_decoder
board_build.filesystem = littlefs
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
@@ -25,6 +28,7 @@ build_flags =
-DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
;-DDEBUG_HEAP
@@ -34,6 +38,7 @@ lib_deps =
${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0
jgromes/RadioLib@^6.1.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
@@ -51,4 +56,4 @@ lib_ignore =
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv
board_build.partitions = partition-table.csv

View File

@@ -1,44 +1,5 @@
[esp32c3_base]
extends = arduino_base
platform = platformio/espressif32@^6.1.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
upload_speed = 961200
extends = esp32_base
monitor_speed = 115200
debug_init_break = tbreak setup
monitor_filters = esp32_c3_exception_decoder
board_build.filesystem = littlefs
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
build_flags =
${arduino_base.build_flags}
-Wall
-Wextra
-Isrc/platform/esp32
-std=c++11
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
;-DDEBUG_HEAP
lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
lib_ignore =
segger_rtt
ESP32 BLE Arduino
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv

View File

@@ -1,47 +1,16 @@
[esp32s2_base]
extends = arduino_base
platform = platformio/espressif32@^6.1.0
extends = esp32_base
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<nimble/>
upload_speed = 961200
${esp32_base.build_src_filter} -<nimble/>
monitor_speed = 115200
debug_init_break = tbreak setup
monitor_filters = esp32_exception_decoder
board_build.filesystem = littlefs
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
build_flags =
${arduino_base.build_flags}
-Wall
-Wextra
-Isrc/platform/esp32
-std=c++11
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DAXP_DEBUG_PORT=Serial
-DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
${esp32_base.build_flags}
-DHAS_BLUETOOTH=0
;-DDEBUG_HEAP
lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
lib_ignore =
segger_rtt
ESP32 BLE Arduino
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv
${esp32_base.lib_ignore}
NimBLE-Arduino

View File

@@ -1,47 +1,5 @@
[esp32s3_base]
extends = arduino_base
platform = platformio/espressif32@^6.1.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
upload_speed = 961200
extends = esp32_base
monitor_speed = 115200
debug_init_break = tbreak setup
monitor_filters = esp32_exception_decoder
board_build.filesystem = littlefs
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
build_flags =
${arduino_base.build_flags}
-Wall
-Wextra
-Isrc/platform/esp32
-std=c++11
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DAXP_DEBUG_PORT=Serial
-DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
;-DDEBUG_HEAP
lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
lib_ignore =
segger_rtt
ESP32 BLE Arduino
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv

View File

@@ -1,18 +1,19 @@
[nrf52_base]
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
platform = platformio/nordicnrf52@^9.5.0
platform = platformio/nordicnrf52@^10.0.0
extends = arduino_base
build_type = debug ; I'm debugging with ICE a lot now
build_flags =
${arduino_base.build_flags} -Wno-unused-variable
-Isrc/platform/nrf52
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/rp2040> -<mesh/eth/>
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/>
lib_deps=
${arduino_base.lib_deps}
jgromes/RadioLib@^6.1.0
lib_ignore =
BluetoothOTA
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:feather_nrf52832]
extends = nrf52_base
board = adafruit_feather_nrf52832
BluetoothOTA

7
arch/nrf52/nrf52832.ini Normal file
View File

@@ -0,0 +1,7 @@
[nrf52832_base]
extends = nrf52_base
build_flags = ${nrf52_base.build_flags}
lib_deps =
${nrf52_base.lib_deps}

View File

@@ -1,14 +1,9 @@
[nrf52840_base]
extends = nrf52_base
build_flags = ${nrf52_base.build_flags}
lib_deps =
${arduino_base.lib_deps}
${nrf52_base.lib_deps}
${environmental_base.lib_deps}
https://github.com/Kongduino/Adafruit_nRFCrypto.git#e31a8825ea3300b163a0a3c1ddd5de34e10e1371
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:nrf52840dk]
extends = nrf52840_base
board = nrf52840_dk

View File

@@ -1,7 +1,8 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
platform = https://github.com/meshtastic/platform-native.git#096b3c3e9c5c8e19d4c3b6cd803fffef2a9be4c5
platform = https://github.com/meshtastic/platform-native.git#489ff929dca0bb768256ba2de45f95815111490f
framework = arduino
build_src_filter =
${env.build_src_filter}
-<platform/esp32/>
@@ -16,8 +17,14 @@ build_src_filter =
-<modules/Telemetry/AirQualityTelemetry.cpp>
-<modules/Telemetry/Sensor>
+<../variants/portduino>
lib_deps =
${env.lib_deps}
${networking_base.lib_deps}
rweather/Crypto@^0.4.0
build_flags = ${arduino_base.build_flags} -fPIC -Isrc/platform/portduino
jgromes/RadioLib@6.1.0
build_flags =
${arduino_base.build_flags}
-fPIC
-Isrc/platform/portduino

View File

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

View File

@@ -1,18 +1,29 @@
[stm32wl5e_base]
platform = platformio/ststm32@^15.4.1
platform_packages = platformio/framework-arduinoststm32 @ https://github.com/stm32duino/Arduino_Core_STM32.git#6e3f9910d0122e82a6c3438507dfac3d2fd80a39
platform = ststm32
board = generic_wl5e
framework = arduino
build_type = debug
build_flags =
${arduino_base.build_flags}
-Isrc/platform/stm32wl -g
-DHAL_SUBGHZ_MODULE_ENABLED
# Arduino/PlatformIO framework-arduinoststm32 package does not presently have SUBGHZSPI support
# -DPIN_SPI_MOSI=PINSUBGHZSPIMOSI -DPIN_SPI_MISO=PINSUBGHZSPIMISO -DPIN_SPI_SCK=PINSUBGHZSPISCK
-DconfigUSE_CMSIS_RTOS_V2=1
-DVECT_TAB_OFFSET=0x08000000
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<mqtt/> -<graphics> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
${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>
board_upload.offset_address = 0x08000000
upload_protocol = stlink
lib_deps =
${env.lib_deps}
jgromes/RadioLib@^6.1.0
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
lib_ignore =
mathertel/OneButton@^2.0.3
https://github.com/littlefs-project/littlefs.git#v2.5.1
https://github.com/stm32duino/STM32FreeRTOS.git#10.3.1
lib_ignore =
https://github.com/mathertel/OneButton#2.1.0

View File

@@ -32,7 +32,7 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
@REM Account for S3 board's different OTA partition
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% (
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% IF x%FILENAME:t-deck=%==x%FILENAME% IF x%FILENAME:wireless-paper=%==x%FILENAME% IF x%FILENAME:wireless-tracker=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin

View File

@@ -50,7 +50,7 @@ if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
# Account for S3 board's different OTA partition
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ]; then
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ] && [ ! -z "${FILENAME##*"t-deck"*}" ] && [ ! -z "${FILENAME##*"wireless-paper"*}" ] && [ ! -z "${FILENAME##*"wireless-tracker"*}" ]; then
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
else
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin

View File

@@ -20,7 +20,7 @@
"maximum_ram_size": 65536,
"maximum_size": 262144,
"protocol": "cmsis-dap",
"protocols": ["cmsis-dap"]
"protocols": ["cmsis-dap", "stlink"]
},
"url": "https://www.st.com/en/microcontrollers-microprocessors/stm32wl-series.html",
"vendor": "ST"

View File

@@ -0,0 +1,38 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv"
},
"core": "esp32",
"extra_flags": [
"-DHELTEC_WIRELESS_TRACKER",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "heltec_wireless_tracker"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "Heltec Wireless Tracker",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://heltec.org/project/wireless-tracker/",
"vendor": "Heltec"
}

51
boards/nano-g2-ultra.json Normal file
View File

@@ -0,0 +1,51 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x8029"],
["0x239A", "0x0029"],
["0x239A", "0x002A"],
["0x239A", "0x802A"]
],
"usb_product": "BQ nRF52840",
"mcu": "nrf52840",
"variant": "nano-g2-ultra",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd"
},
"frameworks": ["arduino"],
"name": "BQ nRF52840",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra",
"vendor": "BQ Consulting"
}

40
boards/t-deck.json Normal file
View File

@@ -0,0 +1,40 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=0"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "t-deck"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "Espressif Systems LilyGO T-Deck (16 MB FLASH, 8 MB PSRAM)",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,
"maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://www.lilygo.cc/en-pl/products/t-deck",
"vendor": "LilyGO"
}

View File

@@ -7,7 +7,10 @@
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [["0x239A", "0x4405"]],
"hwids": [
["0x239A", "0x4405"],
["0x239A", "0x002A"]
],
"usb_product": "TTGO_eink",
"mcu": "nrf52840",
"variant": "t-echo",

38
boards/t-watch-s3.json Normal file
View File

@@ -0,0 +1,38 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DT_WATCH_S3",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"hwids": [["0X303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "t-watch-s3"
},
"connectivity": ["wifi"],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino"],
"name": "LilyGo T-Watch 2020 V3",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"use_1200bps_touch": true,
"wait_for_upload_port": true
},
"url": "http://www.lilygo.cn/",
"vendor": "LilyGo"
}

View File

@@ -0,0 +1,40 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2E8A",
"usb_pid": "0x000A"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-DARDUINO_GENERIC_RP2040 -DRASPBERRY_PI_PICO -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
"f_cpu": "133000000L",
"hwids": [
["0x2E8A", "0x00C0"],
["0x2E8A", "0x000A"]
],
"mcu": "rp2040",
"variant": "WisBlock_RAK11300_Board"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": ["arduino"],
"name": "WisBlock RAK11300",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 2097152,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": ["cmsis-dap", "raspberrypi-swd", "picotool", "picoprobe"]
},
"url": "https://docs.rakwireless.com/",
"vendor": "RAKwireless"
}

View File

@@ -0,0 +1,57 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v7.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_MDBT50Q_RX -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x810B"],
["0x239A", "0x010B"],
["0x239A", "0x810C"]
],
"usb_product": "XIAO-BOOT",
"mcu": "nrf52840",
"variant": "Seeed_XIAO_nRF52840_Sense",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "7.3.0",
"sd_fwid": "0x0123"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd"
},
"frameworks": ["arduino"],
"name": "Seeed Xiao BLE Sense",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"stlink",
"cmsis-dap",
"blackmagic"
],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://www.seeedstudio.com/Seeed-XIAO-BLE-Sense-nRF52840-p-5253.html",
"vendor": "Seeed Studio"
}

View File

@@ -2,17 +2,18 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = tbeam
;default_envs = tbeam
;default_envs = pico
;default_envs = tbeam-s3-core
;default_envs = tbeam0.7
;default_envs = heltec-v1
;default_envs = heltec-v2.0
;default_envs = heltec-v2.1
;default_envs = heltec-v2_0
;default_envs = heltec-v2_1
;default_envs = heltec-wireless-tracker
;default_envs = tlora-v1
;default_envs = tlora_v1_3
;default_envs = tlora-v2
;default_envs = tlora-v2-1-1.6
;default_envs = tlora-v2-1-1_6
;default_envs = tlora-t3s3-v1
;default_envs = lora-relay-v1 # nrf board
;default_envs = t-echo
@@ -21,17 +22,18 @@ default_envs = tbeam
;default_envs = nano-g1
;default_envs = pca10059_diy_eink
;default_envs = meshtastic-diy-v1
;default_envs = meshtastic-diy-v1.1
;default_envs = meshtastic-diy-v1_1
;default_envs = meshtastic-dr-dev
;default_envs = m5stack-coreink
;default_envs = rak4631
default_envs = wio-e5
extra_configs =
arch/*/*.ini
variants/*/platformio.ini
[env]
extra_scripts = bin/platformio-custom.py
extra_scripts = bin/platformio-custom.py
; note: we add src to our include search path so that lmic_project_config can override
; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile
@@ -39,8 +41,8 @@ extra_scripts = bin/platformio-custom.py
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
; The Radiolib stuff will speed up building considerably. Exclud all the stuff we dont need.
build_flags = -Wno-missing-field-initializers
-Wno-format
-Isrc -Isrc/mesh -Isrc/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
-Wno-format
-Isrc -Isrc/mesh -Isrc/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
-DUSE_THREAD_NAMES
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
-DPB_ENABLE_MALLOC=1
@@ -55,20 +57,23 @@ build_flags = -Wno-missing-field-initializers
-DRADIOLIB_EXCLUDE_MORSE
-DRADIOLIB_EXCLUDE_RTTY
-DRADIOLIB_EXCLUDE_SSTV
-DRADIOLIB_EXCLUDE_AX25
-DRADIOLIB_EXCLUDE_DIRECT_RECEIVE
-DRADIOLIB_EXCLUDE_BELL
-DRADIOLIB_EXCLUDE_PAGER
-DRADIOLIB_EXCLUDE_FSK4
-DRADIOLIB_EXCLUDE_APRS
monitor_speed = 115200
lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306
https://github.com/mathertel/OneButton#2.1.0 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1
; temp: do this till > 5.7.0 release to keep (some) SX1262 and SX1280 working - resolves -705 error during init
https://github.com/jgromes/RadioLib.git#45c5859338590b7eede23cb2f95284c3fb0cf08e
; jgromes/RadioLib@^5.7.0
; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck
@@ -90,14 +95,14 @@ lib_deps =
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
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
[networking_base]
lib_deps =
knolleary/PubSubClient@^2.8
arduino-libraries/NTPClient@^3.1.0
arcao/Syslog@^2.0.0
; Common libs for environmental measurements in telemetry module
; Common libs for environmental measurements in telemetry module
; (not included in native / portduino)
[environmental_base]
lib_deps =
@@ -105,7 +110,8 @@ lib_deps =
adafruit/Adafruit Unified Sensor@^1.1.9
adafruit/Adafruit BMP280 Library@^2.6.6
adafruit/Adafruit BME280 Library@^2.2.2
https://github.com/meshtastic/BSEC-Arduino-library.git#452f9a7ffa8b53e1debe2c454fe375dfad98b507
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
boschsensortec/BME68x Sensor Library@^1.1.40407
adafruit/Adafruit MCP9808 Library@^2.0.0
adafruit/Adafruit INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0
@@ -115,3 +121,4 @@ lib_deps =
adafruit/Adafruit PM25 AQI Sensor@^1.0.6
adafruit/Adafruit MPU6050@^2.2.4
adafruit/Adafruit LIS3DH@^1.2.4
https://github.com/lewisxhe/BMA423_Library@^0.0.1

View File

@@ -6,10 +6,37 @@
#include <Adafruit_LIS3DH.h>
#include <Adafruit_MPU6050.h>
#include <Arduino.h>
#include <Wire.h>
#include <bma.h>
BMA423 bmaSensor;
bool BMA_IRQ = false;
#define ACCELEROMETER_CHECK_INTERVAL_MS 100
#define ACCELEROMETER_CLICK_THRESHOLD 40
uint16_t readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
{
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom((uint8_t)address, (uint8_t)len);
uint8_t i = 0;
while (Wire.available()) {
data[i++] = Wire.read();
}
return 0; // Pass
}
uint16_t writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
{
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(data, len);
return (0 != Wire.endTransmission());
}
namespace concurrency
{
class AccelerometerThread : public concurrency::OSThread
@@ -29,10 +56,10 @@ class AccelerometerThread : public concurrency::OSThread
return;
}
accleremoter_type = type;
acceleremoter_type = type;
LOG_DEBUG("AccelerometerThread initializing\n");
if (accleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.begin(accelerometer_found.address)) {
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.begin(accelerometer_found.address)) {
LOG_DEBUG("MPU6050 initializing\n");
// setup motion detection
mpu.setHighPassFilter(MPU6050_HIGHPASS_0_63_HZ);
@@ -40,11 +67,60 @@ class AccelerometerThread : public concurrency::OSThread
mpu.setMotionDetectionDuration(20);
mpu.setInterruptPinLatch(true); // Keep it latched. Will turn off when reinitialized.
mpu.setInterruptPinPolarity(true);
} else if (accleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.begin(accelerometer_found.address)) {
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.begin(accelerometer_found.address)) {
LOG_DEBUG("LIS3DH initializing\n");
lis.setRange(LIS3DH_RANGE_2_G);
// Adjust threshhold, higher numbers are less sensitive
// Adjust threshold, higher numbers are less sensitive
lis.setClick(config.device.double_tap_as_button_press ? 2 : 1, ACCELEROMETER_CLICK_THRESHOLD);
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.begin(readRegister, writeRegister, delay)) {
LOG_DEBUG("BMA423 initializing\n");
Acfg cfg;
cfg.odr = BMA4_OUTPUT_DATA_RATE_100HZ;
cfg.range = BMA4_ACCEL_RANGE_2G;
cfg.bandwidth = BMA4_ACCEL_NORMAL_AVG4;
cfg.perf_mode = BMA4_CONTINUOUS_MODE;
bmaSensor.setAccelConfig(cfg);
bmaSensor.enableAccel();
struct bma4_int_pin_config pin_config;
pin_config.edge_ctrl = BMA4_LEVEL_TRIGGER;
pin_config.lvl = BMA4_ACTIVE_HIGH;
pin_config.od = BMA4_PUSH_PULL;
pin_config.output_en = BMA4_OUTPUT_ENABLE;
pin_config.input_en = BMA4_INPUT_DISABLE;
// The correct trigger interrupt needs to be configured as needed
bmaSensor.setINTPinConfig(pin_config, BMA4_INTR1_MAP);
#ifdef BMA423_INT
pinMode(BMA4XX_INT, INPUT);
attachInterrupt(
BMA4XX_INT,
[] {
// Set interrupt to set irq value to true
BMA_IRQ = true;
},
RISING); // Select the interrupt mode according to the actual circuit
#endif
struct bma423_axes_remap remap_data;
remap_data.x_axis = 0;
remap_data.x_axis_sign = 1;
remap_data.y_axis = 1;
remap_data.y_axis_sign = 0;
remap_data.z_axis = 2;
remap_data.z_axis_sign = 1;
// Need to raise the wrist function, need to set the correct axis
bmaSensor.setRemapAxes(&remap_data);
// sensor.enableFeature(BMA423_STEP_CNTR, true);
bmaSensor.enableFeature(BMA423_TILT, true);
bmaSensor.enableFeature(BMA423_WAKEUP, true);
// sensor.resetStepCounter();
// Turn on feature interrupt
bmaSensor.enableStepCountInterrupt();
bmaSensor.enableTiltInterrupt();
// It corresponds to isDoubleClick interrupt
bmaSensor.enableWakeupInterrupt();
}
}
@@ -53,9 +129,9 @@ class AccelerometerThread : public concurrency::OSThread
{
canSleep = true; // Assume we should not keep the board awake
if (accleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) {
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) {
wakeScreen();
} else if (accleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) {
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) {
uint8_t click = lis.getClick();
if (!config.device.double_tap_as_button_press) {
wakeScreen();
@@ -65,7 +141,13 @@ class AccelerometerThread : public concurrency::OSThread
buttonPress();
return 500;
}
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.getINT()) {
if (bmaSensor.isTilt() || bmaSensor.isDoubleClick()) {
wakeScreen();
return 500;
}
}
return ACCELEROMETER_CHECK_INTERVAL_MS;
}
@@ -84,9 +166,9 @@ class AccelerometerThread : public concurrency::OSThread
powerFSM.trigger(EVENT_PRESS);
}
ScanI2C::DeviceType accleremoter_type;
ScanI2C::DeviceType acceleremoter_type;
Adafruit_MPU6050 mpu;
Adafruit_LIS3DH lis;
};
} // namespace concurrency
} // namespace concurrency

View File

@@ -4,6 +4,7 @@
#include "concurrency/OSThread.h"
#include "configuration.h"
#include "graphics/Screen.h"
#include "main.h"
#include "power.h"
#include <OneButton.h>
@@ -51,7 +52,7 @@ class ButtonThread : public concurrency::OSThread
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP_SENSE);
#endif
userButton.attachClick(userButtonPressed);
userButton.setClickTicks(300);
userButton.setClickMs(300);
userButton.attachDuringLongPress(userButtonPressedLong);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed);
@@ -98,10 +99,10 @@ class ButtonThread : public concurrency::OSThread
userButtonTouch.tick();
canSleep &= userButtonTouch.isIdle();
#endif
// if (!canSleep) LOG_DEBUG("Supressing sleep!\n");
// if (!canSleep) LOG_DEBUG("Suppressing sleep!\n");
// else LOG_DEBUG("sleep ok\n");
return 5;
return 50;
}
private:
@@ -157,7 +158,7 @@ class ButtonThread : public concurrency::OSThread
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
#endif
screen->print("Sent ad-hoc ping\n");
service.refreshMyNodeInfo();
service.refreshLocalMeshNode();
service.sendNetworkPing(NODENUM_BROADCAST, true);
}
@@ -196,4 +197,4 @@ class ButtonThread : public concurrency::OSThread
}
};
} // namespace concurrency
} // namespace concurrency

View File

@@ -28,6 +28,7 @@
#define DEBUG_PORT (*console) // Serial debug port
#ifdef USE_SEGGER
#define DEBUG_PORT
#define LOG_DEBUG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#define LOG_INFO(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#define LOG_WARN(...) SEGGER_RTT_printf(0, __VA_ARGS__)

View File

@@ -8,6 +8,8 @@
#ifdef SDCARD_USE_SPI1
SPIClass SPI1(HSPI);
#define SDHandler SPI1
#else
#define SDHandler SPI
#endif
#endif // HAS_SDCARD
@@ -57,7 +59,7 @@ bool renameFile(const char *pathFrom, const char *pathTo)
#endif
}
void listDir(const char *dirname, uint8_t levels, boolean del = false)
void listDir(const char *dirname, uint8_t levels, bool del = false)
{
#ifdef FSCom
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))

View File

@@ -13,6 +13,13 @@
#define FILE_O_READ "r"
#endif
#if defined(ARCH_STM32WL)
#include "platform/stm32wl/InternalFileSystem.h" // STM32WL version
#define FSCom InternalFS
#define FSBegin() FSCom.begin()
using namespace LittleFS_Namespace;
#endif
#if defined(ARCH_RP2040)
// RP2040
#include "LittleFS.h"
@@ -42,6 +49,6 @@ using namespace Adafruit_LittleFS_Namespace;
void fsInit();
bool copyFile(const char *from, const char *to);
bool renameFile(const char *pathFrom, const char *pathTo);
void listDir(const char *dirname, uint8_t levels, boolean del);
void listDir(const char *dirname, uint8_t levels, bool del);
void rmDir(const char *dirname);
void setupSDCard();

View File

@@ -55,7 +55,7 @@ class GPSStatus : public Status
#ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed latitude\n");
#endif
meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
return node->position.latitude_i;
} else {
return p.latitude_i;
@@ -68,7 +68,7 @@ class GPSStatus : public Status
#ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed longitude\n");
#endif
meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
return node->position.longitude_i;
} else {
return p.longitude_i;
@@ -81,7 +81,7 @@ class GPSStatus : public Status
#ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed altitude\n");
#endif
meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
return node->position.altitude;
} else {
return p.altitude;
@@ -106,7 +106,7 @@ class GPSStatus : public Status
bool matches(const GPSStatus *newStatus) const
{
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp);
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.timestamp, p.timestamp);
#endif
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||
newStatus->isPowerSaving != isPowerSaving || newStatus->p.latitude_i != p.latitude_i ||
@@ -138,8 +138,9 @@ class GPSStatus : public Status
LOG_DEBUG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp,
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
p.ground_speed * 1e-2, p.sats_in_view);
} else
} else {
LOG_DEBUG("No GPS lock\n");
}
onNewStatus.notifyObservers(this);
}
return 0;
@@ -148,4 +149,4 @@ class GPSStatus : public Status
} // namespace meshtastic
extern meshtastic::GPSStatus *gpsStatus;
extern meshtastic::GPSStatus *gpsStatus;

View File

@@ -5,7 +5,8 @@
* Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR)
*
* NOTE! xTimerPend... seems to ignore the time passed in on ESP32 and on NRF52
* The reason this didn't work is bcause xTimerPednFunctCall really isn't a timer function at all - it just means run the callback
* The reason this didn't work is because xTimerPednFunctCall really isn't a timer function at all - it just means run the
callback
* from the timer thread the next time you have spare cycles.
*
* @return true if successful, false if the timer fifo is too full.

View File

@@ -17,14 +17,40 @@
#define DELAY_FOREVER portMAX_DELAY
#endif
#if defined(BATTERY_PIN) && defined(ARCH_ESP32)
#ifndef BAT_MEASURE_ADC_UNIT // ADC1 is default
static const adc1_channel_t adc_channel = ADC_CHANNEL;
static const adc_unit_t unit = ADC_UNIT_1;
#else // ADC2
static const adc2_channel_t adc_channel = ADC_CHANNEL;
static const adc_unit_t unit = ADC_UNIT_2;
RTC_NOINIT_ATTR uint64_t RTC_reg_b;
#endif // BAT_MEASURE_ADC_UNIT
esp_adc_cal_characteristics_t *adc_characs = (esp_adc_cal_characteristics_t *)calloc(1, sizeof(esp_adc_cal_characteristics_t));
#ifndef ADC_ATTENUATION
static const adc_atten_t atten = ADC_ATTEN_DB_11;
#else
static const adc_atten_t atten = ADC_ATTENUATION;
#endif
#endif // BATTERY_PIN && ARCH_ESP32
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
INA260Sensor ina260Sensor;
INA219Sensor ina219Sensor;
#endif
#ifdef HAS_PMU
#include "XPowersAXP192.tpp"
#include "XPowersAXP2101.tpp"
#include "XPowersLibInterface.hpp"
XPowersLibInterface *PMU = NULL;
#else
// Copy of the base class defined in axp20x.h.
// I'd rather not inlude axp20x.h as it brings Wire dependency.
// I'd rather not include axp20x.h as it brings Wire dependency.
class HasBatteryLevel
{
public:
@@ -108,6 +134,13 @@ class AnalogBatteryLevel : public HasBatteryLevel
virtual uint16_t getBattVoltage() override
{
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
if (hasINA()) {
LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address);
return getINAVoltage();
}
#endif
#ifndef ADC_MULTIPLIER
#define ADC_MULTIPLIER 2.0
#endif
@@ -128,18 +161,41 @@ class AnalogBatteryLevel : public HasBatteryLevel
// Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic
// environment.
uint32_t raw = 0;
#ifdef ARCH_ESP32
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += adc1_get_raw(adc_channel);
}
#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
#else // !ARCH_ESP32
for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += analogRead(BATTERY_PIN);
}
#endif
raw = raw / BATTERY_SENSE_SAMPLES;
float scaled;
#ifdef ARCH_ESP32
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
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
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
#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;
return scaled;
} else {
@@ -147,7 +203,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
}
#else
return 0;
#endif
#endif // BATTERY_PIN
}
/**
@@ -203,6 +259,35 @@ class AnalogBatteryLevel : public HasBatteryLevel
const float fullVolt = BAT_FULLVOLT, emptyVolt = BAT_EMPTYVOLT, chargingVolt = BAT_CHARGINGVOLT, noBatVolt = BAT_NOBATVOLT;
float last_read_value = 0.0;
uint32_t last_read_time_ms = 0;
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO)
uint16_t getINAVoltage()
{
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
return ina219Sensor.getBusVoltageMv();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
return ina260Sensor.getBusVoltageMv();
}
return 0;
}
bool hasINA()
{
if (!config.power.device_battery_ina_address) {
return false;
}
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
if (!ina219Sensor.isInitialized())
return ina219Sensor.runOnce() > 0;
return ina219Sensor.isRunning();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
if (!ina260Sensor.isInitialized())
return ina260Sensor.runOnce() > 0;
return ina260Sensor.isRunning();
}
return false;
}
#endif
};
AnalogBatteryLevel analogLevel;
@@ -228,25 +313,52 @@ bool Power::analogInit()
// disable any internal pullups
pinMode(BATTERY_PIN, INPUT);
#ifdef ARCH_ESP32
// ESP32 needs special analog stuff
adcAttachPin(BATTERY_PIN);
#ifndef BATTERY_SENSE_RESOLUTION_BITS
#define BATTERY_SENSE_RESOLUTION_BITS 10
#endif
#ifdef ARCH_ESP32 // ESP32 needs special analog stuff
#ifndef ADC_WIDTH // max resolution by default
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
#else
static const adc_bits_width_t width = ADC_WIDTH;
#endif
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
adc1_config_width(width);
adc1_config_channel_atten(adc_channel, atten);
#else // ADC2
adc2_config_channel_atten(adc_channel, atten);
// ADC2 wifi bug workaround
RTC_reg_b = READ_PERI_REG(SENS_SAR_READ_CTRL2_REG);
#endif
// calibrate ADC
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_characs);
// show ADC characterization base
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
LOG_INFO("ADCmod: ADC characterization based on Two Point values stored in eFuse\n");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
LOG_INFO("ADCmod: ADC characterization based on reference voltage stored in eFuse\n");
} else {
LOG_INFO("ADCmod: ADC characterization based on default reference voltage\n");
}
#if defined(HELTEC_V3) || defined(HELTEC_WSL_V3)
pinMode(37, OUTPUT); // needed for P channel mosfet to work
digitalWrite(37, LOW);
#endif
#endif // ARCH_ESP32
#ifdef ARCH_NRF52
#ifdef VBAT_AR_INTERNAL
analogReference(VBAT_AR_INTERNAL);
#else
analogReference(AR_INTERNAL); // 3.6V
#endif
#endif
#ifndef BATTERY_SENSE_RESOLUTION_BITS
#define BATTERY_SENSE_RESOLUTION_BITS 10
#endif
// adcStart(BATTERY_PIN);
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11
// depending on needed resolution.
#endif // ARCH_NRF52
batteryLevel = &analogLevel;
return true;
#else
@@ -302,7 +414,7 @@ void Power::readPowerStatus()
{
if (batteryLevel) {
bool hasBattery = batteryLevel->isBatteryConnect();
int batteryVoltageMv = 0;
uint32_t batteryVoltageMv = 0;
int8_t batteryChargePercent = 0;
if (hasBattery) {
batteryVoltageMv = batteryLevel->getBattVoltage();
@@ -365,8 +477,8 @@ void Power::readPowerStatus()
#endif
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 10 low readings in a
// row
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 10 low readings in
// a row
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) {
low_voltage_counter++;
@@ -428,10 +540,12 @@ int32_t Power::runOnce()
LOG_DEBUG("Battery removed\n");
}
*/
#ifndef T_WATCH_S3 // FIXME - why is this triggering on the T-Watch S3?
if (PMU->isPekeyLongPressIrq()) {
LOG_DEBUG("PEK long button press\n");
screen->setOn(false);
}
#endif
PMU->clearIrqStatus();
}
@@ -444,10 +558,10 @@ int32_t Power::runOnce()
* Init the power manager chip
*
* axp192 power
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the axp192
share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this on!) LDO1
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the
axp192 share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this
on!) LDO1 30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of
days), can not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
*
*/
bool Power::axpChipInit()
@@ -540,82 +654,88 @@ bool Power::axpChipInit()
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
/*The alternative version of T-Beam 1.1 differs from T-Beam V1.1 in that it uses an AXP2101 power chip*/
#if (HW_VENDOR == meshtastic_HardwareModel_TBEAM)
// Unuse power channel
PMU->disablePowerOutput(XPOWERS_DCDC2);
PMU->disablePowerOutput(XPOWERS_DCDC3);
PMU->disablePowerOutput(XPOWERS_DCDC4);
PMU->disablePowerOutput(XPOWERS_DCDC5);
PMU->disablePowerOutput(XPOWERS_ALDO1);
PMU->disablePowerOutput(XPOWERS_ALDO4);
PMU->disablePowerOutput(XPOWERS_BLDO1);
PMU->disablePowerOutput(XPOWERS_BLDO2);
PMU->disablePowerOutput(XPOWERS_DLDO1);
PMU->disablePowerOutput(XPOWERS_DLDO2);
if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) {
// Unuse power channel
PMU->disablePowerOutput(XPOWERS_DCDC2);
PMU->disablePowerOutput(XPOWERS_DCDC3);
PMU->disablePowerOutput(XPOWERS_DCDC4);
PMU->disablePowerOutput(XPOWERS_DCDC5);
PMU->disablePowerOutput(XPOWERS_ALDO1);
PMU->disablePowerOutput(XPOWERS_ALDO4);
PMU->disablePowerOutput(XPOWERS_BLDO1);
PMU->disablePowerOutput(XPOWERS_BLDO2);
PMU->disablePowerOutput(XPOWERS_DLDO1);
PMU->disablePowerOutput(XPOWERS_DLDO2);
// GNSS RTC PowerVDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
PMU->enablePowerOutput(XPOWERS_VBACKUP);
// GNSS RTC PowerVDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
PMU->enablePowerOutput(XPOWERS_VBACKUP);
// ESP32 VDD 3300mV
// ! No need to set, automatically open , Don't close it
// PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
// PMU->setProtectedChannel(XPOWERS_DCDC1);
// ESP32 VDD 3300mV
// ! No need to set, automatically open , Don't close it
// PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
// PMU->setProtectedChannel(XPOWERS_DCDC1);
// LoRa VDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO2);
// LoRa VDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO2);
// GNSS VDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
// GNSS VDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
} else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE ||
HW_VENDOR == meshtastic_HardwareModel_T_WATCH_S3) {
// t-beam s3 core
/**
* gnss module power channel
* The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during
* initialization
*/
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO4);
#elif (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE)
// t-beam s3 core
/**
* gnss module power channel
* The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during initialization
*/
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO4);
// lora radio power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
// lora radio power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
// m.2 interface
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC3);
// m.2 interface
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC3);
/**
* ALDO2 cannot be turned off.
* It is a necessary condition for sensor communication.
* It must be turned on to properly access the sensor and screen
* It is also responsible for the power supply of PCF8563
*/
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO2);
/**
* ALDO2 cannot be turned off.
* It is a necessary condition for sensor communication.
* It must be turned on to properly access the sensor and screen
* It is also responsible for the power supply of PCF8563
*/
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO2);
// 6-axis , magnetometer ,bme280 , oled screen power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO1);
// 6-axis , magnetometer ,bme280 , oled screen power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO1);
// sdcard power channle
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
PMU->enablePowerOutput(XPOWERS_BLDO1);
// PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
// PMU->enablePowerOutput(XPOWERS_DCDC4);
// not use channel
PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited
PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited
PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist
PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist
PMU->disablePowerOutput(XPOWERS_VBACKUP);
// sdcard power channel
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
PMU->enablePowerOutput(XPOWERS_BLDO1);
#ifdef T_WATCH_S3
// DRV2605 power channel
PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
PMU->enablePowerOutput(XPOWERS_BLDO2);
#endif
// PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
// PMU->enablePowerOutput(XPOWERS_DCDC4);
// not use channel
PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited
PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited
PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist
PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist
PMU->disablePowerOutput(XPOWERS_VBACKUP);
}
// disable all axp chip interrupt
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);

View File

@@ -35,7 +35,7 @@ static bool isPowered()
static void sdsEnter()
{
LOG_INFO("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
doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs));
}
@@ -44,7 +44,7 @@ extern Power *power;
static void shutdownEnter()
{
LOG_INFO("Enter state: SHUTDOWN\n");
LOG_DEBUG("Enter state: SHUTDOWN\n");
power->shutdown();
}
@@ -135,7 +135,7 @@ static void lsExit()
static void nbEnter()
{
LOG_INFO("Enter state: NB\n");
LOG_DEBUG("Enter state: NB\n");
screen->setOn(false);
setBluetoothEnable(false);
@@ -150,7 +150,7 @@ static void darkEnter()
static void serialEnter()
{
LOG_INFO("Enter state: SERIAL\n");
LOG_DEBUG("Enter state: SERIAL\n");
setBluetoothEnable(false);
screen->setOn(true);
screen->print("Serial connected\n");
@@ -163,7 +163,7 @@ static void serialExit()
static void powerEnter()
{
LOG_INFO("Enter state: POWER\n");
LOG_DEBUG("Enter state: POWER\n");
if (!isPowered()) {
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
LOG_INFO("Loss of power in Powered\n");
@@ -198,7 +198,7 @@ static void powerExit()
static void onEnter()
{
LOG_INFO("Enter state: ON\n");
LOG_DEBUG("Enter state: ON\n");
screen->setOn(true);
setBluetoothEnable(true);
}
@@ -218,7 +218,7 @@ static void screenPress()
static void bootEnter()
{
LOG_INFO("Enter state: BOOT\n");
LOG_DEBUG("Enter state: BOOT\n");
}
State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN");
@@ -352,5 +352,5 @@ void PowerFSM_setup()
"mesh timeout");
#endif
powerFSM.run_machine(); // run one interation 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
}

View File

@@ -62,6 +62,9 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
{
if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, "DEBUG") == 0) {
return 0;
}
size_t r = 0;
if (!inDebugPrint) {

View File

@@ -31,7 +31,7 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
Port.begin(SERIAL_BAUD);
#if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
#if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(ARCH_RP2040)
time_t timeout = millis();
while (!Port) {
if ((millis() - timeout) < 5000) {

View File

@@ -6,20 +6,22 @@ AirTime *airTime = NULL;
// Don't read out of this directly. Use the helper functions.
uint32_t air_period_tx[PERIODS_TO_LOG];
uint32_t air_period_rx[PERIODS_TO_LOG];
void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
{
if (reportType == TX_LOG) {
LOG_DEBUG("AirTime - Packet transmitted : %ums\n", airtime_ms);
this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms;
myNodeInfo.air_period_tx[0] = myNodeInfo.air_period_tx[0] + airtime_ms;
air_period_tx[0] = air_period_tx[0] + airtime_ms;
this->utilizationTX[this->getPeriodUtilHour()] = this->utilizationTX[this->getPeriodUtilHour()] + airtime_ms;
} else if (reportType == RX_LOG) {
LOG_DEBUG("AirTime - Packet received : %ums\n", airtime_ms);
this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms;
myNodeInfo.air_period_rx[0] = myNodeInfo.air_period_rx[0] + airtime_ms;
air_period_rx[0] = air_period_rx[0] + airtime_ms;
} else if (reportType == RX_ALL_LOG) {
LOG_DEBUG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms;
@@ -55,16 +57,16 @@ void AirTime::airtimeRotatePeriod()
this->airtimes.periodRX[i + 1] = this->airtimes.periodRX[i];
this->airtimes.periodRX_ALL[i + 1] = this->airtimes.periodRX_ALL[i];
myNodeInfo.air_period_tx[i + 1] = this->airtimes.periodTX[i];
myNodeInfo.air_period_rx[i + 1] = this->airtimes.periodRX[i];
air_period_tx[i + 1] = this->airtimes.periodTX[i];
air_period_rx[i + 1] = this->airtimes.periodRX[i];
}
this->airtimes.periodTX[0] = 0;
this->airtimes.periodRX[0] = 0;
this->airtimes.periodRX_ALL[0] = 0;
myNodeInfo.air_period_tx[0] = 0;
myNodeInfo.air_period_rx[0] = 0;
air_period_tx[0] = 0;
air_period_rx[0] = 0;
this->airtimes.lastPeriodIndex = this->currentPeriodIndex();
}
@@ -179,18 +181,17 @@ int32_t AirTime::runOnce()
}
// Init airtime windows to all 0
for (int i = 0; i < myNodeInfo.air_period_rx_count; i++) {
for (int i = 0; i < PERIODS_TO_LOG; i++) {
this->airtimes.periodTX[i] = 0;
this->airtimes.periodRX[i] = 0;
this->airtimes.periodRX_ALL[i] = 0;
// myNodeInfo.air_period_tx[i] = 0;
// myNodeInfo.air_period_rx[i] = 0;
// air_period_tx[i] = 0;
// air_period_rx[i] = 0;
}
firstTime = false;
lastUtilPeriod = utilPeriod;
} else {
this->airtimeRotatePeriod();
@@ -206,12 +207,6 @@ int32_t AirTime::runOnce()
this->utilizationTX[utilPeriodTX] = 0;
}
// Update channel_utilization every second.
myNodeInfo.channel_utilization = airTime->channelUtilizationPercent();
// Update channel_utilization every second.
myNodeInfo.air_util_tx = airTime->utilizationTXPercent();
}
/*
LOG_DEBUG("utilPeriodTX %d TX Airtime %3.2f%\n", utilPeriodTX, airTime->utilizationTXPercent());
@@ -223,4 +218,4 @@ int32_t AirTime::runOnce()
LOG_DEBUG("\n");
*/
return (1000 * 1);
}
}

View File

@@ -17,9 +17,9 @@
Example analytics:
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel.
TX_LOG + RX_LOG = Total air time for a particular meshtastic channel.
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including
TX_LOG + RX_LOG = Total air time for a particular meshtastic channel, including
other lora radios.
RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.

View File

@@ -15,4 +15,6 @@ enum class Cmd {
PRINT,
START_SHUTDOWN_SCREEN,
START_REBOOT_SCREEN,
SHOW_PREV_FRAME,
SHOW_NEXT_FRAME
};

View File

@@ -18,7 +18,7 @@ namespace concurrency
*
* Useful for they top level loop() delay call to keep the CPU powered down until our next scheduled event or some external event.
*
* This is implmented for FreeRTOS but should be easy to port to other operating systems.
* This is implemented for FreeRTOS but should be easy to port to other operating systems.
*/
class InterruptableDelay
{

View File

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

View File

@@ -61,14 +61,17 @@ bool OSThread::shouldRun(unsigned long time)
{
bool r = Thread::shouldRun(time);
if (showRun && r)
if (showRun && r) {
LOG_DEBUG("Thread %s: run\n", ThreadName.c_str());
}
if (showWaiting && enabled && !r)
if (showWaiting && enabled && !r) {
LOG_DEBUG("Thread %s: wait %lu\n", ThreadName.c_str(), interval);
}
if (showDisabled && !enabled)
if (showDisabled && !enabled) {
LOG_DEBUG("Thread %s: disabled\n", ThreadName.c_str());
}
return r;
}

View File

@@ -98,8 +98,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Define if screen should be mirrored left to right
// #define SCREEN_MIRROR
// The m5stack I2C Keyboard (also RAK14004)
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
#define CARDKB_ADDR 0x5F
#define TDECK_KB_ADDR 0x55
// -----------------------------------------------------------------------------
// SENSOR
@@ -123,6 +124,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
#define MPU6050_ADDR 0x68
#define LIS3DH_ADR 0x18
#define BMA423_ADDR 0x19
// -----------------------------------------------------------------------------
// LED
// -----------------------------------------------------------------------------
#define NCP5623_ADDR 0x38
// -----------------------------------------------------------------------------
// Security
@@ -167,6 +174,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef HAS_BUTTON
#define HAS_BUTTON 0
#endif
#ifndef HAS_TRACKBALL
#define HAS_TRACKBALL 0
#endif
#ifndef HAS_TOUCHSCREEN
#define HAS_TOUCHSCREEN 0
#endif
#ifndef HAS_TELEMETRY
#define HAS_TELEMETRY 0
#endif
@@ -188,4 +201,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef HW_VENDOR
#error HW_VENDOR must be defined
#endif
#endif

View File

@@ -30,14 +30,14 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
ScanI2C::DeviceType types[] = {CARDKB, RAK14004};
return firstOfOrNONE(2, types);
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, RAK14004};
return firstOfOrNONE(3, types);
}
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
{
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH};
return firstOfOrNONE(2, types);
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423};
return firstOfOrNONE(3, types);
}
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const
@@ -73,4 +73,4 @@ bool ScanI2C::DeviceAddress::operator<(const ScanI2C::DeviceAddress &other) cons
|| (port != NO_I2C && other.port != NO_I2C && (address < other.address));
}
ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {}
ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {}

View File

@@ -16,6 +16,7 @@ class ScanI2C
RTC_RV3028,
RTC_PCF8563,
CARDKB,
TDECKKB,
RAK14004,
PMU_AXP192_AXP2101,
BME_680,
@@ -33,6 +34,10 @@ class ScanI2C
PMSA0031,
MPU6050,
LIS3DH,
BMA423,
#ifdef HAS_NCP5623
NCP5623,
#endif
} DeviceType;
// typedef uint8_t DeviceAddress;
@@ -94,4 +99,4 @@ class ScanI2C
private:
bool shouldSuppressScreen = false;
};
};

View File

@@ -212,8 +212,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
}
break;
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n")
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
#ifdef HAS_NCP5623
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
#endif
#ifdef HAS_PMU
SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found\n")
#endif
@@ -272,6 +275,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n")
SCAN_SIMPLE_CASE(MPU6050_ADDR, MPU6050, "MPU6050 accelerometer found\n");
SCAN_SIMPLE_CASE(BMA423_ADDR, BMA423, "BMA423 accelerometer found\n");
default:
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
@@ -290,7 +294,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
{
if (address.port == ScanI2C::I2CPort::WIRE1) {
if (address.port == ScanI2C::I2CPort::WIRE) {
return &Wire;
} else {
#ifdef I2C_SDA1
@@ -304,4 +308,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
}
}

View File

@@ -1,6 +1,6 @@
#include "../configuration.h"
#ifdef RAK4630
#ifdef RAK_4631
#include "../main.h"
#include <SPI.h>
@@ -64,4 +64,4 @@ void scanEInkDevice(void)
LOG_DEBUG("EInk display not found\n");
SPI1.end();
}
#endif
#endif

View File

@@ -9,4 +9,4 @@
/// Record an error that should be reported via analytics
void recordCriticalError(meshtastic_CriticalErrorCode code = meshtastic_CriticalErrorCode_UNSPECIFIED, uint32_t address = 0,
const char *filename = NULL);
const char *filename = NULL);

View File

@@ -12,7 +12,7 @@
#include <freertos/task.h>
#endif
#if defined(ARDUINO_NRF52_ADAFRUIT)
#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_RP2040)
#define HAS_FREE_RTOS
#include <FreeRTOS.h>
@@ -44,4 +44,4 @@ typedef uint32_t BaseType_t;
enum eNotifyAction { eNoAction, eSetValueWithoutOverwrite, eSetValueWithOverwrite };
#endif
#endif

View File

@@ -4,6 +4,10 @@
#include "configuration.h"
#include "sleep.h"
#ifndef GPS_RESET_MODE
#define GPS_RESET_MODE HIGH
#endif
// If we have a serial GPS port it will not be null
#ifdef GPS_SERIAL_NUM
HardwareSerial _serial_gps_real(GPS_SERIAL_NUM);
@@ -21,11 +25,29 @@ GPS *gps;
/// only init that port once.
static bool didSerialInit;
bool GPS::getACK(uint8_t c, uint8_t i)
struct uBloxGnssModelInfo info;
uint8_t uBloxProtocolVersion;
void GPS::UBXChecksum(byte *message, size_t length)
{
uint8_t CK_A = 0, CK_B = 0;
// Calculate the checksum, starting from the CLASS field (which is message[2])
for (size_t i = 2; i < length - 2; i++) {
CK_A = (CK_A + message[i]) & 0xFF;
CK_B = (CK_B + CK_A) & 0xFF;
}
// Place the calculated checksum values in the message
message[length - 2] = CK_A;
message[length - 1] = CK_B;
}
bool GPS::getACK(uint8_t class_id, uint8_t msg_id)
{
uint8_t b;
uint8_t ack = 0;
const uint8_t ackP[2] = {c, i};
const uint8_t ackP[2] = {class_id, msg_id};
uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned long startTime = millis();
@@ -42,17 +64,23 @@ bool GPS::getACK(uint8_t c, uint8_t i)
while (1) {
if (ack > 9) {
return true;
// LOG_INFO("Got ACK for class %02X message %02X\n", class_id, msg_id);
return true; // ACK received
}
if (millis() - startTime > 1000) {
return false;
if (millis() - startTime > 3000) {
LOG_WARN("No response for class %02X message %02X\n", class_id, msg_id);
return false; // No response received within 3 seconds
}
if (_serial_gps->available()) {
b = _serial_gps->read();
if (b == buf[ack]) {
ack++;
} else {
ack = 0;
ack = 0; // Reset the acknowledgement counter
if (buf[3] == 0x00) { // UBX-ACK-NAK message
LOG_WARN("Got NAK for class %02X message %02X\n", class_id, msg_id);
return false; // NAK received
}
}
}
}
@@ -73,7 +101,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
uint32_t startTime = millis();
uint16_t needRead;
while (millis() - startTime < 800) {
while (millis() - startTime < 1200) {
while (_serial_gps->available()) {
int c = _serial_gps->read();
switch (ubxFrameCounter) {
@@ -108,12 +136,12 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
}
break;
case 4:
// Payload lenght lsb
// Payload length lsb
needRead = c;
ubxFrameCounter++;
break;
case 5:
// Payload lenght msb
// Payload length msb
needRead |= (c << 8);
ubxFrameCounter++;
break;
@@ -126,7 +154,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
if (_serial_gps->readBytes(buffer, needRead) != needRead) {
ubxFrameCounter = 0;
} else {
// return payload lenght
// return payload length
return needRead;
}
break;
@@ -160,10 +188,14 @@ bool GPS::setupGPS()
config.position.tx_gpio = GPS_TX_PIN;
#endif
//#define BAUD_RATE 115200
// ESP32 has a special set of parameters vs other arduino ports
#if defined(ARCH_ESP32)
if (config.position.rx_gpio)
if (config.position.rx_gpio) {
LOG_DEBUG("Using GPIO%d for GPS RX\n", config.position.rx_gpio);
LOG_DEBUG("Using GPIO%d for GPS TX\n", config.position.tx_gpio);
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, config.position.rx_gpio, config.position.tx_gpio);
}
#else
_serial_gps->begin(GPS_BAUDRATE);
#endif
@@ -190,8 +222,131 @@ bool GPS::setupGPS()
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
_serial_gps->write("$PCAS11,3*1E\r\n");
delay(250);
} else if (gnssModel == GNSS_MODEL_UC6850) {
// use GPS + GLONASS
_serial_gps->write("$CFGSYS,h15\r\n");
delay(250);
} else if (gnssModel == GNSS_MODEL_UBLOX) {
// Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command)
// We need set it because by default it is GPS only, and we want to use GLONASS too
// Also we need SBAS for better accuracy and extra features
// ToDo: Dynamic configure GNSS systems depending of LoRa region
byte _message_GNSS[36] = {
0xb5, 0x62, // Sync message for UBX protocol
0x06, 0x3e, // Message class and ID (UBX-CFG-GNSS)
0x1c, 0x00, // Length of payload (28 bytes)
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
0x00, 0x00 // Checksum (to be calculated below)
};
// Calculate the checksum and update the message.
UBXChecksum(_message_GNSS, sizeof(_message_GNSS));
// Send the message to the module
_serial_gps->write(_message_GNSS, sizeof(_message_GNSS));
if (!getACK(0x06, 0x3e)) {
// 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.
LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n");
return true;
} else {
LOG_INFO("GNSS configured for GPS+SBAS+GLONASS. Pause for 0.75s before sending next command.\n");
// Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next commands
delay(750);
return true;
}
// Enable interference resistance, because we are using LoRa, WiFi and Bluetooth on same board,
// and we need to reduce interference from them
byte _message_JAM[16] = {
0xB5, 0x62, // UBX protocol sync characters
0x06, 0x39, // Message class and ID (UBX-CFG-ITFM)
0x08, 0x00, // Length of payload (8 bytes)
// bbThreshold (Broadband jamming detection threshold) is set to 0x3F (63 in decimal)
// cwThreshold (CW jamming detection threshold) is set to 0x10 (16 in decimal)
// algorithmBits (Reserved algorithm settings) is set to 0x16B156 as recommended
// enable (Enable interference detection) is set to 1 (enabled)
0x3F, 0x10, 0xB1, 0x56, // config: Interference config word
// generalBits (General settings) is set to 0x31E as recommended
// antSetting (Antenna setting, 0=unknown, 1=passive, 2=active) is set to 0 (unknown)
// ToDo: Set to 1 (passive) or 2 (active) if known, for example from UBX-MON-HW, or from board info
// enable2 (Set to 1 to scan auxiliary bands, u-blox 8 / u-blox M8 only, otherwise ignored) is set to 1
// (enabled)
0x1E, 0x03, 0x00, 0x01, // config2: Extra settings for jamming/interference monitor
0x00, 0x00 // Checksum (calculated below)
};
// Calculate the checksum and update the message.
UBXChecksum(_message_JAM, sizeof(_message_JAM));
// Send the message to the module
_serial_gps->write(_message_JAM, sizeof(_message_JAM));
if (!getACK(0x06, 0x39)) {
LOG_WARN("Unable to enable interference resistance.\n");
return true;
}
// Configure navigation engine expert settings:
byte _message_NAVX5[48] = {
0xb5, 0x62, // UBX protocol sync characters
0x06, 0x23, // Message class and ID (UBX-CFG-NAVX5)
0x28, 0x00, // Length of payload (40 bytes)
0x00, 0x00, // msgVer (0 for this version)
// minMax flag = 1: apply min/max SVs settings
// minCno flag = 1: apply minimum C/N0 setting
// initial3dfix flag = 0: apply initial 3D fix settings
// aop flag = 1: apply aopCfg (useAOP flag) settings (AssistNow Autonomous)
0x1B, 0x00, // mask1 (First parameters bitmask)
// adr flag = 0: apply ADR sensor fusion on/off setting (useAdr flag)
// If firmware is not ADR/UDR, enabling this flag will fail configuration
// ToDo: check this with UBX-MON-VER
0x00, 0x00, 0x00, 0x00, // mask2 (Second parameters bitmask)
0x00, 0x00, // Reserved
0x03, // minSVs (Minimum number of satellites for navigation) = 3
0x10, // maxSVs (Maximum number of satellites for navigation) = 16
0x06, // minCNO (Minimum satellite signal level for navigation) = 6 dBHz
0x00, // Reserved
0x00, // iniFix3D (Initial fix must be 3D) = 0 (disabled)
0x00, 0x00, // Reserved
0x00, // ackAiding (Issue acknowledgements for assistance message input) = 0 (disabled)
0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved
0x00, // Reserved
0x01, // aopCfg (AssistNow Autonomous configuration) = 1 (enabled)
0x00, 0x00, // Reserved
0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00, // Reserved
0x00, 0x00, 0x00, // Reserved
0x01, // useAdr (Enable/disable ADR sensor fusion) = 1 (enabled)
0x00, 0x00 // Checksum (calculated below)
};
// Calculate the checksum and update the message.
UBXChecksum(_message_NAVX5, sizeof(_message_NAVX5));
// Send the message to the module
_serial_gps->write(_message_NAVX5, sizeof(_message_NAVX5));
if (!getACK(0x06, 0x23)) {
LOG_WARN("Unable to configure extra settings.\n");
return true;
}
/*
tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after
setting will not output command messages in UART1, resulting in unrecognized module information
@@ -208,57 +363,205 @@ bool GPS::setupGPS()
// ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid
// disable GGL
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A};
// 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.
byte _message_1Hz[] = {
0xB5, 0x62, // UBX protocol sync characters
0x06, 0x08, // Message class and ID (UBX-CFG-RATE)
0x06, 0x00, // Length of payload (6 bytes)
0xE8, 0x03, // Measurement Rate (1000ms for 1Hz)
0x01, 0x00, // Navigation rate, always 1 in GPS mode
0x01, 0x00, // Time reference
0x00, 0x00 // Placeholder for checksum, will be calculated next
};
// Calculate the checksum and update the message.
UBXChecksum(_message_1Hz, sizeof(_message_1Hz));
// Send the message to the module
_serial_gps->write(_message_1Hz, sizeof(_message_1Hz));
if (!getACK(0x06, 0x08)) {
LOG_WARN("Unable to set GPS update rate.\n");
return true;
}
// Disable GGL. GGL - Geographic position (latitude and longitude), which provides the current geographical
// coordinates.
byte _message_GGL[] = {
0xB5, 0x62, // UBX sync characters
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
0x08, 0x00, // Length of payload (8 bytes)
0xF0, 0x01, // NMEA ID for GLL
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x00, // Disable
0x01, 0x01, 0x01, 0x01, // Reserved
0x00, 0x00 // CK_A and CK_B (Checksum)
};
// Calculate the checksum and update the message.
UBXChecksum(_message_GGL, sizeof(_message_GGL));
// Send the message to the module
_serial_gps->write(_message_GGL, sizeof(_message_GGL));
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA GGL.\n");
return true;
}
// disable GSA
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41};
// Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
// the DOP (Dilution of Precision)
byte _message_GSA[] = {
0xB5, 0x62, // UBX sync characters
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
0x08, 0x00, // Length of payload (8 bytes)
0xF0, 0x02, // NMEA ID for GSA
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x01, // Enable
0x01, 0x01, 0x01, 0x01, // Reserved
0x00, 0x00 // CK_A and CK_B (Checksum)
};
UBXChecksum(_message_GSA, sizeof(_message_GSA));
_serial_gps->write(_message_GSA, sizeof(_message_GSA));
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA GSA.\n");
LOG_WARN("Unable to Enable NMEA GSA.\n");
return true;
}
// disable GSV
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48};
// Disable GSV. GSV - Satellites in view, details the number and location of satellites in view.
byte _message_GSV[] = {
0xB5, 0x62, // UBX sync characters
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
0x08, 0x00, // Length of payload (8 bytes)
0xF0, 0x03, // NMEA ID for GSV
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x00, // Disable
0x01, 0x01, 0x01, 0x01, // Reserved
0x00, 0x00 // CK_A and CK_B (Checksum)
};
UBXChecksum(_message_GSV, sizeof(_message_GSV));
_serial_gps->write(_message_GSV, sizeof(_message_GSV));
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA GSV.\n");
return true;
}
// disable VTG
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56};
// Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to
// the ground.
byte _message_VTG[] = {
0xB5, 0x62, // UBX sync characters
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
0x08, 0x00, // Length of payload (8 bytes)
0xF0, 0x05, // NMEA ID for VTG
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x00, // Disable
0x01, 0x01, 0x01, 0x01, // Reserved
0x00, 0x00 // CK_A and CK_B (Checksum)
};
UBXChecksum(_message_VTG, sizeof(_message_VTG));
_serial_gps->write(_message_VTG, sizeof(_message_VTG));
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA VTG.\n");
return true;
}
// enable RMC
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54};
// Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data.
byte _message_RMC[] = {
0xB5, 0x62, // UBX sync characters
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
0x08, 0x00, // Length of payload (8 bytes)
0xF0, 0x04, // NMEA ID for RMC
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x01, // Enable
0x01, 0x01, 0x01, 0x01, // Reserved
0x00, 0x00 // CK_A and CK_B (Checksum)
};
UBXChecksum(_message_RMC, sizeof(_message_RMC));
_serial_gps->write(_message_RMC, sizeof(_message_RMC));
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to enable NMEA RMC.\n");
return true;
}
// enable GGA
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38};
// Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data.
byte _message_GGA[] = {
0xB5, 0x62, // UBX sync characters
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
0x08, 0x00, // Length of payload (8 bytes)
0xF0, 0x00, // NMEA ID for GGA
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x01, // Enable
0x01, 0x01, 0x01, 0x01, // Reserved
0x00, 0x00 // CK_A and CK_B (Checksum)
};
UBXChecksum(_message_GGA, sizeof(_message_GGA));
_serial_gps->write(_message_GGA, sizeof(_message_GGA));
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to enable NMEA GGA.\n");
return true;
}
// 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'.
byte UBX_CFG_PMS[14] = {
0xB5, 0x62, // UBX sync characters
0x06, 0x86, // Message class and ID (UBX-CFG-PMS)
0x06, 0x00, // Length of payload (6 bytes)
0x00, // Version (0)
0x03, // Power setup value
0x00, 0x00, // period: not applicable, set to 0
0x00, 0x00, // onTime: not applicable, set to 0
0x00, 0x00 // Placeholder for checksum, will be calculated next
};
// Calculate the checksum and update the message
UBXChecksum(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
// Send the message to the module
_serial_gps->write(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
if (!getACK(0x06, 0x86)) {
LOG_WARN("Unable to enable powersaving for GPS.\n");
return true;
}
// We need save configuration to flash to make our config changes persistent
byte _message_SAVE[21] = {
0xB5, 0x62, // UBX protocol header
0x06, 0x09, // UBX class ID (Configuration Input Messages), message ID (UBX-CFG-CFG)
0x0D, 0x00, // Length of payload (13 bytes)
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x0F, // deviceMask: BBR, Flash, EEPROM, and SPI Flash
0x00, 0x00 // Checksum (calculated below)
};
// Calculate the checksum and update the message.
UBXChecksum(_message_SAVE, sizeof(_message_SAVE));
// Send the message to the module
_serial_gps->write(_message_SAVE, sizeof(_message_SAVE));
if (!getACK(0x06, 0x09)) {
LOG_WARN("Unable to save GNSS module configuration.\n");
return true;
} else {
LOG_INFO("GNSS module configuration saved!\n");
return true;
}
}
}
@@ -269,22 +572,21 @@ bool GPS::setupGPS()
bool GPS::setup()
{
// Master power for the GPS
#ifdef PIN_GPS_EN
digitalWrite(PIN_GPS_EN, 1);
pinMode(PIN_GPS_EN, OUTPUT);
#endif
#ifdef HAS_PMU
#if defined(HAS_PMU) || defined(PIN_GPS_EN)
if (config.position.gps_enabled) {
#ifdef PIN_GPS_EN
pinMode(PIN_GPS_EN, OUTPUT);
#endif
setGPSPower(true);
}
#endif
#ifdef PIN_GPS_RESET
digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
pinMode(PIN_GPS_RESET, OUTPUT);
delay(10);
digitalWrite(PIN_GPS_RESET, 0);
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
#endif
setAwake(true); // Wake GPS power before doing any init
bool ok = setupGPS();
@@ -384,7 +686,7 @@ void GPS::setAwake(bool on)
}
}
/** Get how long we should stay looking for each aquisition in msecs
/** Get how long we should stay looking for each acquisition in msecs
*/
uint32_t GPS::getWakeTime() const
{
@@ -555,21 +857,17 @@ int GPS::prepareDeepSleep(void *unused)
GnssModel_t GPS::probe()
{
// return immediately if the model is set by the variant.h file
#ifdef GPS_UBLOX
return GNSS_MODEL_UBLOX;
#elif defined(GPS_L76K)
return GNSS_MODEL_MTK;
#else
// we use autodetect, only T-BEAM S3 for now...
uint8_t buffer[256];
/*
* The GNSS module information variable is temporarily placed inside the function body,
* if it needs to be used elsewhere, it can be moved to the outside
* */
struct uBloxGnssModelInfo info;
memset(&info, 0, sizeof(struct uBloxGnssModelInfo));
// return immediately if the model is set by the variant.h file
//#ifdef GPS_UBLOX (unless it's a ublox, because we might want to know the module info!
// return GNSS_MODEL_UBLOX; think about removing this macro and return)
#if defined(GPS_L76K)
return GNSS_MODEL_MTK;
#elif defined(GPS_UC6580)
_serial_gps->updateBaudRate(115200);
return GNSS_MODEL_UC6850;
#else
uint8_t buffer[384] = {0};
// Close all NMEA sentences , Only valid for MTK platform
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
@@ -597,31 +895,37 @@ GnssModel_t GPS::probe()
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
// Check that the returned response class and message ID are correct
if (!getAck(buffer, 256, 0x06, 0x08)) {
if (!getAck(buffer, 384, 0x06, 0x08)) {
LOG_WARN("Failed to find UBlox & MTK GNSS Module\n");
return GNSS_MODEL_UNKONW;
return GNSS_MODEL_UNKNOWN;
}
memset(buffer, 0, sizeof(buffer));
byte _message_MONVER[8] = {
0xB5, 0x62, // Sync message for UBX protocol
0x0A, 0x04, // Message class and ID (UBX-MON-VER)
0x00, 0x00, // Length of payload (we're asking for an answer, so no payload)
0x00, 0x00 // Checksum
};
// Get Ublox gnss module hardware and software info
uint8_t cfg_get_hw[] = {0xB5, 0x62, 0x0A, 0x04, 0x00, 0x00, 0x0E, 0x34};
_serial_gps->write(cfg_get_hw, sizeof(cfg_get_hw));
UBXChecksum(_message_MONVER, sizeof(_message_MONVER));
_serial_gps->write(_message_MONVER, sizeof(_message_MONVER));
uint16_t len = getAck(buffer, 256, 0x0A, 0x04);
uint16_t len = getAck(buffer, 384, 0x0A, 0x04);
if (len) {
// LOG_DEBUG("monver reply size = %d\n", len);
uint16_t position = 0;
for (int i = 0; i < 30; i++) {
info.swVersion[i] = buffer[position];
position++;
}
for (int i = 0; i < 10; i++) {
info.hwVersion[i] = buffer[position];
info.hwVersion[i] = buffer[position - 1];
position++;
}
while (len >= position + 30) {
for (int i = 0; i < 30; i++) {
info.extension[info.extensionNo][i] = buffer[position];
info.extension[info.extensionNo][i] = buffer[position - 1];
position++;
}
info.extensionNo++;
@@ -631,6 +935,7 @@ GnssModel_t GPS::probe()
LOG_DEBUG("Module Info : \n");
LOG_DEBUG("Soft version: %s\n", info.swVersion);
LOG_DEBUG("first char is %c\n", (char)info.swVersion[0]);
LOG_DEBUG("Hard version: %s\n", info.hwVersion);
LOG_DEBUG("Extensions:%d\n", info.extensionNo);
for (int i = 0; i < info.extensionNo; i++) {
@@ -641,19 +946,29 @@ GnssModel_t GPS::probe()
// tips: extensionNo field is 0 on some 6M GNSS modules
for (int i = 0; i < info.extensionNo; ++i) {
if (!strncmp(info.extension[i], "OD=", 3)) {
strncpy((char *)buffer, &(info.extension[i][3]), sizeof(buffer));
LOG_DEBUG("GetModel:%s\n", (char *)buffer);
if (!strncmp(info.extension[i], "MOD=", 4)) {
strncpy((char *)buffer, &(info.extension[i][4]), sizeof(buffer));
// LOG_DEBUG("GetModel:%s\n", (char *)buffer);
if (strlen((char *)buffer)) {
LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n", (char *)buffer);
} else {
LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
}
} else if (!strncmp(info.extension[i], "PROTVER=", 8)) {
char *ptr = nullptr;
memset(buffer, 0, sizeof(buffer));
strncpy((char *)buffer, &(info.extension[i][8]), sizeof(buffer));
LOG_DEBUG("Protocol Version:%s\n", (char *)buffer);
if (strlen((char *)buffer)) {
uBloxProtocolVersion = strtoul((char *)buffer, &ptr, 10);
LOG_DEBUG("ProtVer=%d\n", uBloxProtocolVersion);
} else {
uBloxProtocolVersion = 0;
}
}
}
}
if (strlen((char *)buffer)) {
LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n", buffer);
} else {
LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
}
return GNSS_MODEL_UBLOX;
#endif
}
@@ -675,8 +990,8 @@ GPS *createGps()
LOG_DEBUG("Using MSL altitude model\n");
#endif
if (GPS::_serial_gps) {
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NMEA at 9600 baud.
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all.
// Just assume NMEA at 9600 baud.
GPS *new_gps = new NMEAGPS();
new_gps->setup();
return new_gps;
@@ -688,4 +1003,4 @@ GPS *createGps()
}
return nullptr;
#endif
}
}

View File

@@ -14,7 +14,8 @@ struct uBloxGnssModelInfo {
typedef enum {
GNSS_MODEL_MTK,
GNSS_MODEL_UBLOX,
GNSS_MODEL_UNKONW,
GNSS_MODEL_UC6850,
GNSS_MODEL_UNKNOWN,
} GnssModel_t;
// Generate a string representation of DOP
@@ -139,6 +140,9 @@ class GPS : private concurrency::OSThread
/// 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
*
@@ -164,6 +168,7 @@ class GPS : private concurrency::OSThread
virtual int32_t runOnce() override;
// Get GNSS model
String getNMEA();
GnssModel_t probe();
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
@@ -172,11 +177,11 @@ class GPS : private concurrency::OSThread
uint8_t fixeddelayCtr = 0;
protected:
GnssModel_t gnssModel = GNSS_MODEL_UNKONW;
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;

View File

@@ -12,7 +12,7 @@ GeoCoord::GeoCoord(int32_t lat, int32_t lon, int32_t alt) : _latitude(lat), _lon
GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt)
{
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
// Change decimial representation to int32_t. I.e., 12.345 becomes 123450000
_latitude = int32_t(lat * 1e+7);
_longitude = int32_t(lon * 1e+7);
GeoCoord::setCoords();
@@ -20,7 +20,7 @@ GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt)
GeoCoord::GeoCoord(double lat, double lon, int32_t alt) : _altitude(alt)
{
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
// Change decimial representation to int32_t. I.e., 12.345 becomes 123450000
_latitude = int32_t(lat * 1e+7);
_longitude = int32_t(lon * 1e+7);
GeoCoord::setCoords();
@@ -41,7 +41,7 @@ void GeoCoord::setCoords()
void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt)
{
// If marked dirty or new coordiantes
// If marked dirty or new coordinates
if (_dirty || _latitude != lat || _longitude != lon || _altitude != alt) {
_dirty = true;
_latitude = lat;
@@ -55,7 +55,7 @@ void GeoCoord::updateCoords(const double lat, const double lon, const int32_t al
{
int32_t iLat = lat * 1e+7;
int32_t iLon = lon * 1e+7;
// If marked dirty or new coordiantes
// If marked dirty or new coordinates
if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
_dirty = true;
_latitude = iLat;
@@ -69,7 +69,7 @@ void GeoCoord::updateCoords(const float lat, const float lon, const int32_t alt)
{
int32_t iLat = lat * 1e+7;
int32_t iLon = lon * 1e+7;
// If marked dirty or new coordiantes
// If marked dirty or new coordinates
if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
_dirty = true;
_latitude = iLat;
@@ -217,7 +217,7 @@ void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr)
double eta2 = v / rho - 1;
double mA = (1 + n + (5 / 4) * n * n + (5 / 4) * n * n * n) * (phi - phi0);
double mB = (3 * n + 3 * n * n + (21 / 8) * n * n * n) * sin(phi - phi0) * cos(phi + phi0);
// loss of precision in mC & mD due to floating point rounding can cause innaccuracy of northing by a few meters
// loss of precision in mC & mD due to floating point rounding can cause inaccuracy of northing by a few meters
double mC = (15 / 8 * n * n + 15 / 8 * n * n * n) * sin(2 * (phi - phi0)) * cos(2 * (phi + phi0));
double mD = (35 / 24) * n * n * n * sin(3 * (phi - phi0)) * cos(3 * (phi + phi0));
double m = b * f0 * (mA - mB + mC - mD);

View File

@@ -65,7 +65,7 @@ struct MGRS {
uint32_t northing;
};
// A struct to hold the data for a OSGR coordiante
// A struct to hold the data for a OSGR coordinate
struct OSGR {
char e100k;
char n100k;

View File

@@ -1,5 +1,7 @@
#include "NMEAWPL.h"
#include "GeoCoord.h"
#include "RTC.h"
#include <time.h>
/* -------------------------------------------
* 1 2 3 4 5 6
@@ -16,10 +18,11 @@
* -------------------------------------------
*/
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name)
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_PositionLite &pos, const char *name, bool isCaltopoMode)
{
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
uint32_t len = snprintf(buf, bufsz, "$GNWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", geoCoord.getDMSLatDeg(),
char type = isCaltopoMode ? 'P' : 'N';
uint32_t len = snprintf(buf, bufsz, "$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(),
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(),
geoCoord.getDMSLonDeg(), (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
geoCoord.getDMSLonCP(), name);
@@ -31,6 +34,21 @@ uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const
return len;
}
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name, bool isCaltopoMode)
{
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
char type = isCaltopoMode ? 'P' : 'N';
uint32_t len = snprintf(buf, bufsz, "$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(),
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(),
geoCoord.getDMSLonDeg(), (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
geoCoord.getDMSLonCP(), name);
uint32_t chk = 0;
for (uint32_t i = 1; i < len; i++) {
chk ^= buf[i];
}
len += snprintf(buf + len, bufsz - len, "*%02X\r\n", chk);
return len;
}
/* -------------------------------------------
* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
* | | | | | | | | | | | | | | |
@@ -56,12 +74,18 @@ uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const
uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos)
{
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
uint32_t len =
snprintf(buf, bufsz, "$GNGGA,%06u.%03u,%02d%07.4f,%c,%03d%07.4f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d", pos.time / 1000,
pos.time % 1000, geoCoord.getDMSLatDeg(), (abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6,
geoCoord.getDMSLatCP(), geoCoord.getDMSLonDeg(),
(abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6, geoCoord.getDMSLonCP(), pos.fix_type,
pos.sats_in_view, pos.HDOP, geoCoord.getAltitude(), 'M', pos.altitude_geoidal_separation, 'M', 0, 0);
tm *t = localtime((time_t *)&pos.timestamp);
if (getRTCQuality() > 0) { // use the device clock if we got time from somewhere. If not, use the GPS timestamp.
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
t = localtime((time_t *)&rtc_sec);
}
uint32_t len = snprintf(
buf, bufsz, "$GNGGA,%02d%02d%02d.%02d,%02d%07.4f,%c,%03d%07.4f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d", t->tm_hour,
t->tm_min, t->tm_sec, pos.timestamp_millis_adjust, geoCoord.getDMSLatDeg(),
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(), geoCoord.getDMSLonDeg(),
(abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6, geoCoord.getDMSLonCP(), pos.fix_quality,
pos.sats_in_view, pos.HDOP, geoCoord.getAltitude(), 'M', pos.altitude_geoidal_separation, 'M', 0, 0);
uint32_t chk = 0;
for (uint32_t i = 1; i < len; i++) {

View File

@@ -3,5 +3,6 @@
#include "main.h"
#include <Arduino.h>
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name);
uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos);
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name, bool isCaltopoMode = false);
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_PositionLite &pos, const char *name, bool isCaltopoMode = false);
uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos);

View File

@@ -19,7 +19,7 @@ static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only upda
void readFromRTC()
{
struct timeval tv; /* btw settimeofday() is helpfull here too*/
struct timeval tv; /* btw settimeofday() is helpful here too*/
#ifdef RV3028_RTC
if (rtc_found.address == RV3028_RTC) {
uint32_t now = millis();

View File

@@ -7,6 +7,10 @@
#include "main.h"
#include <SPI.h>
// #ifdef HELTEC_WIRELESS_PAPER
// SPIClass *hspi = NULL;
// #endif
#define COLORED GxEPD_BLACK
#define UNCOLORED GxEPD_WHITE
@@ -19,13 +23,13 @@
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
// 4.2 inch 300x400 - GxEPD2_420_M01
//#define TECHO_DISPLAY_MODEL GxEPD2_420_M01
// #define TECHO_DISPLAY_MODEL GxEPD2_420_M01
// 2.9 inch 296x128 - GxEPD2_290_T5D
//#define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
// #define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
// 1.54 inch 200x200 - GxEPD2_154_M09
//#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
// #define TECHO_DISPLAY_MODEL GxEPD2_154_M09
#elif defined(MAKERPYTHON)
// 2.9 inch 296x128 - GxEPD2_290_T5D
@@ -41,6 +45,9 @@
// 1.54 inch 200x200 - GxEPD2_154_M09
#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
#elif defined(HELTEC_WIRELESS_PAPER)
//#define TECHO_DISPLAY_MODEL GxEPD2_213_T5D
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
#endif
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
@@ -62,6 +69,10 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY
// GxEPD2_154_M09
// setGeometry(GEOMETRY_RAWMODE, 200, 200);
#elif defined(HELTEC_WIRELESS_PAPER)
// setGeometry(GEOMETRY_RAWMODE, 212, 104);
setGeometry(GEOMETRY_RAWMODE, 250, 122);
#elif defined(MAKERPYTHON)
// GxEPD2_290_T5D
setGeometry(GEOMETRY_RAWMODE, 296, 128);
@@ -109,7 +120,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
for (uint32_t y = 0; y < displayHeight; y++) {
for (uint32_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient
auto b = buffer[x + (y / 8) * displayWidth];
auto isset = b & (1 << (y & 7));
adafruitDisplay->drawPixel(x, y, isset ? COLORED : UNCOLORED);
@@ -218,6 +229,16 @@ bool EInkDisplay::connect()
(void)adafruitDisplay;
}
}
#elif defined(HELTEC_WIRELESS_PAPER)
{
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
// hspi = new SPIClass(HSPI);
// 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->setPartialWindow(0, 0, displayWidth, displayHeight);
}
#elif defined(PCA10059)
{
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);

7
src/graphics/RAKled.h Normal file
View File

@@ -0,0 +1,7 @@
#include "main.h"
#ifdef HAS_NCP5623
#include <NCP5623.h>
extern NCP5623 rgb;
#endif

View File

@@ -27,9 +27,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "error.h"
#include "gps/GeoCoord.h"
#include "gps/RTC.h"
#include "graphics/images.h"
#include "input/TouchScreenImpl1.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "mesh/Channels.h"
@@ -101,7 +103,7 @@ static uint16_t displayWidth, displayHeight;
#define SCREEN_WIDTH displayWidth
#define SCREEN_HEIGHT displayHeight
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
// The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
@@ -295,7 +297,7 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
int x_offset = display->width() / 2;
int y_offset = display->height() == 64 ? 0 : 32;
int y_offset = display->height() <= 80 ? 0 : 32;
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(x_offset + x, y_offset + y, "Bluetooth");
@@ -319,18 +321,18 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
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(64 + x, 26 + y, "Shutting down...");
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(64 + x, 26 + y, "Rebooting...");
display->drawString(x_offset + x, 26 + y, "Rebooting...");
}
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
@@ -352,14 +354,14 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
display->setFont(FONT_MEDIUM);
char tempBuf[24];
snprintf(tempBuf, sizeof(tempBuf), "Critical fault #%d", myNodeInfo.error_code);
snprintf(tempBuf, sizeof(tempBuf), "Critical fault #%d", error_code);
display->drawString(0 + x, 0 + y, tempBuf);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org");
}
// Ignore messages orginating 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)
{
return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled;
@@ -372,7 +374,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
static char tempBuf[237];
meshtastic_MeshPacket &mp = devicestate.rx_text_message;
meshtastic_NodeInfo *node = nodeDB.getNode(getFrom(&mp));
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
// LOG_DEBUG("drawing text message from 0x%x: %s\n", mp.from,
// mp.decoded.variant.data.decoded.bytes);
@@ -410,7 +412,7 @@ static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, i
static char tempBuf[237];
meshtastic_MeshPacket &mp = devicestate.rx_waypoint;
meshtastic_NodeInfo *node = nodeDB.getNode(getFrom(&mp));
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
@@ -441,7 +443,7 @@ static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, i
}
}
/// Draw a series of fields in a column, wrapping to multiple colums if needed
/// Draw a series of fields in a column, wrapping to multiple columns if needed
static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
{
// The coordinates define the left starting point of the text
@@ -491,7 +493,7 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
{
char usersString[20];
snprintf(usersString, sizeof(usersString), "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
display->drawFastImage(x, y + 3, 8, 8, imgUser);
#else
display->drawFastImage(x, y, 8, 8, imgUser);
@@ -711,13 +713,6 @@ static float estimatedHeading(double lat, double lon)
return b;
}
/// Sometimes we will have Position objects that only have a time, so check for
/// valid lat/lon
static bool hasPosition(meshtastic_NodeInfo *n)
{
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
}
static uint16_t getCompassDiam(OLEDDisplay *display)
{
uint16_t diam = 0;
@@ -799,16 +794,16 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
if (state->currentFrame != prevFrame) {
prevFrame = state->currentFrame;
nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes();
meshtastic_NodeInfo *n = nodeDB.getNodeByIndex(nodeIndex);
nodeIndex = (nodeIndex + 1) % nodeDB.getNumMeshNodes();
meshtastic_NodeInfoLite *n = nodeDB.getMeshNodeByIndex(nodeIndex);
if (n->num == nodeDB.getNodeNum()) {
// Don't show our node, just skip to next
nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes();
n = nodeDB.getNodeByIndex(nodeIndex);
nodeIndex = (nodeIndex + 1) % nodeDB.getNumMeshNodes();
n = nodeDB.getMeshNodeByIndex(nodeIndex);
}
}
meshtastic_NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex);
meshtastic_NodeInfoLite *node = nodeDB.getMeshNodeByIndex(nodeIndex);
display->setFont(FONT_SMALL);
@@ -841,8 +836,12 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
}
static char distStr[20];
strncpy(distStr, "? km", sizeof(distStr)); // might not have location data
meshtastic_NodeInfo *ourNode = nodeDB.getNode(nodeDB.getNodeNum());
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
strncpy(distStr, "? mi", sizeof(distStr)); // might not have location data
} else {
strncpy(distStr, "? km", sizeof(distStr));
}
meshtastic_NodeInfoLite *ourNode = nodeDB.getMeshNode(nodeDB.getNodeNum());
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
int16_t compassX = 0, compassY = 0;
@@ -856,15 +855,15 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
}
bool hasNodeHeading = false;
if (ourNode && hasPosition(ourNode)) {
meshtastic_Position &op = ourNode->position;
if (ourNode && hasValidPosition(ourNode)) {
meshtastic_PositionLite &op = ourNode->position;
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
drawCompassNorth(display, compassX, compassY, myHeading);
if (hasPosition(node)) {
if (hasValidPosition(node)) {
// display direction toward node
hasNodeHeading = true;
meshtastic_Position &p = node->position;
meshtastic_PositionLite &p = node->position;
float d =
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
@@ -892,7 +891,8 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
if (!hasNodeHeading) {
// direction to node is unknown so display question mark
// Debug info for gps lock errors
// LOG_DEBUG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
// LOG_DEBUG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasValidPosition(ourNode),
// hasValidPosition(node));
display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
}
display->drawCircle(compassX, compassY, getCompassDiam(display) / 2);
@@ -949,6 +949,9 @@ void Screen::handleSetOn(bool on)
if (on != screenOn) {
if (on) {
LOG_INFO("Turning on screen\n");
#ifdef T_WATCH_S3
PMU->enablePowerOutput(XPOWERS_ALDO2);
#endif
dispdev.displayOn();
dispdev.displayOn();
enabled = true;
@@ -957,6 +960,9 @@ void Screen::handleSetOn(bool on)
} else {
LOG_INFO("Turning off screen\n");
dispdev.displayOff();
#ifdef T_WATCH_S3
PMU->disablePowerOutput(XPOWERS_ALDO2);
#endif
enabled = false;
}
screenOn = on;
@@ -1039,12 +1045,18 @@ void Screen::setup()
#endif
serialSinceMsec = millis();
#if HAS_TOUCHSCREEN
touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch);
touchScreenImpl1->init();
#endif
// Subscribe to status updates
powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
if (textMessageModule)
textMessageObserver.observe(textMessageModule);
inputObserver.observe(inputBroker);
// Modules can notify screen about refresh
MeshModule::observeUIEvents(&uiFrameEventObserver);
@@ -1122,6 +1134,12 @@ int32_t Screen::runOnce()
handleOnPress();
}
break;
case Cmd::SHOW_PREV_FRAME:
handleShowPrevFrame();
break;
case Cmd::SHOW_NEXT_FRAME:
handleShowNextFrame();
break;
case Cmd::START_BLUETOOTH_PIN_SCREEN:
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
break;
@@ -1239,13 +1257,15 @@ void Screen::setFrames()
moduleFrames = MeshModule::GetMeshModulesWithUIFrames();
LOG_DEBUG("Showing %d module frames\n", moduleFrames.size());
#ifdef DEBUG_PORT
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.size();
LOG_DEBUG("Total frame count: %d\n", totalFrameCount);
#endif
// We don't show the node info our our node (if we have it yet - we should)
size_t numnodes = nodeDB.getNumNodes();
if (numnodes > 0)
numnodes--;
size_t numMeshNodes = nodeDB.getNumMeshNodes();
if (numMeshNodes > 0)
numMeshNodes--;
size_t numframes = 0;
@@ -1262,7 +1282,7 @@ void Screen::setFrames()
LOG_DEBUG("Added modules. numframes: %d\n", numframes);
// If we have a critical fault, show it first
if (myNodeInfo.error_code)
if (error_code)
normalFrames[numframes++] = drawCriticalFaultFrame;
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
@@ -1276,7 +1296,7 @@ void Screen::setFrames()
// then all the nodes
// We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens
size_t numToShow = min(numnodes, 4U);
size_t numToShow = min(numMeshNodes, 4U);
for (size_t i = 0; i < numToShow; i++)
normalFrames[numframes++] = drawNodeInfo;
@@ -1413,6 +1433,28 @@ void Screen::handleOnPress()
}
}
void Screen::handleShowPrevFrame()
{
// 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 (ui.getUiState()->frameState == FIXED) {
ui.previousFrame();
lastScreenTransition = millis();
setFastFramerate();
}
}
void Screen::handleShowNextFrame()
{
// 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 (ui.getUiState()->frameState == FIXED) {
ui.nextFrame();
lastScreenTransition = millis();
setFastFramerate();
}
}
#ifndef SCREEN_TRANSITION_FRAMERATE
#define SCREEN_TRANSITION_FRAMERATE 30 // fps
#endif
@@ -1485,7 +1527,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
#ifdef ARCH_ESP32
if (millis() - storeForwardModule->lastHeartbeat >
(storeForwardModule->heartbeatInterval * 1200)) { // no heartbeat, overlap a bit
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
imgQuestionL1);
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
@@ -1495,7 +1537,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
imgQuestion);
#endif
} else {
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8,
imgSFL1);
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8,
@@ -1507,7 +1549,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
}
#endif
} else {
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
imgInfoL1);
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
@@ -1792,7 +1834,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
heartbeat = !heartbeat;
#endif
}
// adjust Brightness cycle trough 1 to 254 as long as attachDuringLongPress is true
// adjust Brightness cycle through 1 to 254 as long as attachDuringLongPress is true
void Screen::adjustBrightness()
{
if (!useDisplay)
@@ -1850,7 +1892,21 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
return 0;
}
int Screen::handleInputEvent(const InputEvent *event)
{
if (showingNormalScreen && moduleFrames.size() == 0) {
LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
showPrevFrame();
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
showNextFrame();
}
}
return 0;
}
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
#endif // HAS_SCREEN
#endif // HAS_SCREEN

View File

@@ -53,6 +53,7 @@ class Screen
#include "commands.h"
#include "concurrency/LockGuard.h"
#include "concurrency/OSThread.h"
#include "input/InputBroker.h"
#include "mesh/MeshModule.h"
#include "power.h"
#include <string>
@@ -118,6 +119,8 @@ class Screen : public concurrency::OSThread
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
CallbackObserver<Screen, const InputEvent *> inputObserver =
CallbackObserver<Screen, const InputEvent *>(this, &Screen::handleInputEvent);
public:
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
@@ -152,8 +155,10 @@ class Screen : public concurrency::OSThread
void blink();
/// Handles a button press.
/// Handle button press, trackball or swipe action)
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); }
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
// Implementation to Adjust Brightness
void adjustBrightness();
@@ -301,9 +306,11 @@ class Screen : public concurrency::OSThread
// Use this handle to set things like battery status, user count, GPS status, etc.
DebugInfo *debug_info() { return &debugInfo; }
// Handle observer events
int handleStatusUpdate(const meshtastic::Status *arg);
int handleTextMessage(const meshtastic_MeshPacket *arg);
int handleUIFrameEvent(const UIFrameEvent *arg);
int handleInputEvent(const InputEvent *arg);
/// Used to force (super slow) eink displays to draw critical frames
void forceDisplay();
@@ -343,6 +350,8 @@ class Screen : public concurrency::OSThread
// Implementations of various commands, called from doTask().
void handleSetOn(bool on);
void handleOnPress();
void handleShowNextFrame();
void handleShowPrevFrame();
void handleStartBluetoothPinScreen(uint32_t pin);
void handlePrint(const char *text);
void handleStartFirmwareUpdateScreen();
@@ -380,7 +389,7 @@ class Screen : public concurrency::OSThread
SH1106Wire dispdev;
#elif defined(USE_SSD1306)
SSD1306Wire dispdev;
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
TFTDisplay dispdev;
#elif defined(USE_EINK)
EInkDisplay dispdev;
@@ -394,4 +403,4 @@ class Screen : public concurrency::OSThread
};
} // namespace graphics
#endif
#endif

View File

@@ -1,12 +1,233 @@
#include "configuration.h"
#if defined(ST7735_CS) || defined(ILI9341_DRIVER)
#ifndef TFT_BACKLIGHT_ON
#define TFT_BACKLIGHT_ON HIGH
#endif
// convert 24-bit color to 16-bit (56K)
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
#if defined(ST7735S)
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
#if defined(ST7735_BACKLIGHT_EN) && !defined(TFT_BL)
#define TFT_BL ST7735_BACKLIGHT_EN
#endif
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ST7735S _panel_instance;
lgfx::Bus_SPI _bus_instance;
lgfx::Light_PWM _light_instance;
public:
LGFX(void)
{
{
auto cfg = _bus_instance.config();
// configure SPI
cfg.spi_host = ST7735_SPI_HOST; // ESP32-S2,S3,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
cfg.spi_mode = 0;
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
// 80MHz by an integer)
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
cfg.use_lock = true; // Set to true to use transaction locking
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
// SPI_DMA_CH_AUTO=auto setting)
cfg.pin_sclk = ST7735_SCK; // Set SPI SCLK pin number
cfg.pin_mosi = ST7735_SDA; // Set SPI MOSI pin number
cfg.pin_miso = ST7735_MISO; // Set SPI MISO pin number (-1 = disable)
cfg.pin_dc = ST7735_RS; // Set SPI DC pin number (-1 = disable)
_bus_instance.config(cfg); // applies the set value to the bus.
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
}
{ // Set the display panel control.
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
cfg.pin_cs = ST7735_CS; // Pin number where CS is connected (-1 = disable)
cfg.pin_rst = ST7735_RESET; // Pin number where RST is connected (-1 = disable)
cfg.pin_busy = ST7735_BUSY; // Pin number where BUSY is connected (-1 = disable)
// The following setting values are general initial values for each panel, so please comment out any
// unknown items and try them.
cfg.panel_width = TFT_WIDTH; // actual displayable width
cfg.panel_height = TFT_HEIGHT; // actual displayable height
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is upside down)
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.readable = true; // Set to true if data can be read
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
cfg.dlen_16bit =
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
// ST7735 or ILI9163.
cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
_panel_instance.config(cfg);
}
// Set the backlight control
{
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
cfg.pin_bl = ST7735_BL; // Pin number to which the backlight is connected
cfg.invert = true; // true to invert the brightness of the backlight
// cfg.freq = 44100; // PWM frequency of backlight
// cfg.pwm_channel = 1; // PWM channel number to use
_light_instance.config(cfg);
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
}
setPanel(&_panel_instance);
}
};
static LGFX tft;
#elif defined(ST7789_CS)
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
#if defined(ST7789_BACKLIGHT_EN) && !defined(TFT_BL)
#define TFT_BL ST7789_BACKLIGHT_EN
#endif
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ST7789 _panel_instance;
lgfx::Bus_SPI _bus_instance;
lgfx::Light_PWM _light_instance;
#ifdef T_WATCH_S3
lgfx::Touch_FT5x06 _touch_instance;
#else
lgfx::Touch_GT911 _touch_instance;
#endif
public:
LGFX(void)
{
{
auto cfg = _bus_instance.config();
// SPI
cfg.spi_host = ST7789_SPI_HOST;
cfg.spi_mode = 0;
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
// 80MHz by an integer)
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
cfg.use_lock = true; // Set to true to use transaction locking
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
cfg.pin_sclk = ST7789_SCK; // Set SPI SCLK pin number
cfg.pin_mosi = ST7789_SDA; // Set SPI MOSI pin number
cfg.pin_miso = ST7789_MISO; // Set SPI MISO pin number (-1 = disable)
cfg.pin_dc = ST7789_RS; // Set SPI DC pin number (-1 = disable)
_bus_instance.config(cfg); // applies the set value to the bus.
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
}
{ // Set the display panel control.
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
cfg.pin_cs = ST7789_CS; // Pin number where CS is connected (-1 = disable)
cfg.pin_rst = -1; // Pin number where RST is connected (-1 = disable)
cfg.pin_busy = -1; // Pin number where BUSY is connected (-1 = disable)
// The following setting values are general initial values for each panel, so please comment out any
// unknown items and try them.
cfg.panel_width = TFT_WIDTH; // actual displayable width
cfg.panel_height = TFT_HEIGHT; // actual displayable height
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
cfg.readable = true; // Set to true if data can be read
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
cfg.dlen_16bit =
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
// ST7735 or ILI9163.
// cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
// cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
_panel_instance.config(cfg);
}
// Set the backlight control. (delete if not necessary)
{
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
cfg.pin_bl = ST7789_BL; // Pin number to which the backlight is connected
cfg.invert = false; // true to invert the brightness of the backlight
// cfg.pwm_channel = 0;
_light_instance.config(cfg);
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
}
// Configure settings for touch screen control.
{
auto cfg = _touch_instance.config();
cfg.pin_cs = -1;
cfg.x_min = 0;
cfg.x_max = TFT_HEIGHT - 1;
cfg.y_min = 0;
cfg.y_max = TFT_WIDTH - 1;
cfg.pin_int = SCREEN_TOUCH_INT;
cfg.bus_shared = true;
cfg.offset_rotation = 0;
// cfg.freq = 2500000;
// I2C
cfg.i2c_port = TOUCH_I2C_PORT;
cfg.i2c_addr = TOUCH_SLAVE_ADDRESS;
#ifdef SCREEN_TOUCH_USE_I2C1
cfg.pin_sda = I2C_SDA1;
cfg.pin_scl = I2C_SCL1;
#else
cfg.pin_sda = I2C_SDA;
cfg.pin_scl = I2C_SCL;
#endif
// cfg.freq = 400000;
_touch_instance.config(cfg);
_panel_instance.setTouch(&_touch_instance);
}
setPanel(&_panel_instance); // Sets the panel to use.
}
};
static LGFX tft;
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
#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
#endif
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER)
#include "SPILock.h"
#include "TFTDisplay.h"
#include <SPI.h>
#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{
@@ -30,7 +251,7 @@ void TFTDisplay::display(void)
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
if (isset != dblbuf_isset) {
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
tft.drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
}
}
}
@@ -46,8 +267,55 @@ void TFTDisplay::display(void)
// Send a command to the display (low level function)
void TFTDisplay::sendCommand(uint8_t com)
{
(void)com;
// Drop all commands to device (we just update the buffer)
// handle display on/off directly
switch (com) {
case DISPLAYON: {
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
#endif
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, LOW);
#endif
#ifndef M5STACK
tft.setBrightness(128);
#endif
break;
}
case DISPLAYOFF: {
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON);
#endif
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, HIGH);
#endif
#ifndef M5STACK
tft.setBrightness(0);
#endif
break;
}
default:
break;
}
// Drop all other commands to device (we just update the buffer)
}
bool TFTDisplay::hasTouch(void)
{
#ifndef M5STACK
return tft.touch() != nullptr;
#else
return false;
#endif
}
bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
{
#ifndef M5STACK
return tft.getTouch(x, y);
#else
return false;
#endif
}
void TFTDisplay::setDetected(uint8_t detected)
@@ -62,23 +330,20 @@ bool TFTDisplay::connect()
LOG_INFO("Doing TFT init\n");
#ifdef TFT_BL
digitalWrite(TFT_BL, HIGH);
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
pinMode(TFT_BL, OUTPUT);
#endif
#ifdef ST7735_BACKLIGHT_EN
digitalWrite(ST7735_BACKLIGHT_EN, HIGH);
pinMode(ST7735_BACKLIGHT_EN, OUTPUT);
#endif
tft.init();
#ifdef M5STACK
tft.setRotation(1); // M5Stack has the TFT in landscape
#if defined(M5STACK) || defined(T_DECK)
tft.setRotation(1); // M5Stack/T-Deck have the TFT in landscape
#elif defined(T_WATCH_S3)
tft.setRotation(0); // T-Watch S3 has the TFT in portrait
#else
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
#endif
tft.fillScreen(TFT_BLACK);
// tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left
return true;
}
#endif
#endif

View File

@@ -7,7 +7,6 @@
*
* Remaining TODO:
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
* implement displayOn/displayOff to turn off the TFT device (and backlight)
* Use the fast NRF52 SPI API rather than the slow standard arduino version
*
* turn radio back on - currently with both on spi bus is fucked? or are we leaving chip select asserted?
@@ -23,6 +22,10 @@ class TFTDisplay : public OLEDDisplay
// Write the buffer to the display memory
virtual void display(void) override;
// Touch screen (static handlers)
static bool hasTouch(void);
static bool getTouch(int16_t *x, int16_t *y);
/**
* shim to make the abstraction happy
*
@@ -38,4 +41,4 @@ class TFTDisplay : public OLEDDisplay
// Connect to the display
virtual bool connect() override;
};
};

View File

@@ -14,7 +14,7 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
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 imgInfoL1[] PROGMEM = {0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff};

View File

@@ -0,0 +1,137 @@
#include "TouchScreenBase.h"
#include "main.h"
#ifndef TIME_LONG_PRESS
#define TIME_LONG_PRESS 400
#endif
// move a minimum distance over the screen to detect a "swipe"
#ifndef TOUCH_THRESHOLD_X
#define TOUCH_THRESHOLD_X 30
#endif
#ifndef TOUCH_THRESHOLD_Y
#define TOUCH_THRESHOLD_Y 20
#endif
TouchScreenBase::TouchScreenBase(const char *name, uint16_t width, uint16_t height)
: concurrency::OSThread(name), _display_width(width), _display_height(height), _first_x(0), _last_x(0), _first_y(0),
_last_y(0), _start(0), _tapped(false), _originName(name)
{
}
void TouchScreenBase::init(bool hasTouch)
{
if (hasTouch) {
LOG_INFO("TouchScreen initialized %d %d\n", TOUCH_THRESHOLD_X, TOUCH_THRESHOLD_Y);
this->setInterval(100);
} else {
disable();
this->setInterval(UINT_MAX);
}
}
int32_t TouchScreenBase::runOnce()
{
TouchEvent e;
e.touchEvent = static_cast<char>(TOUCH_ACTION_NONE);
// process touch events
int16_t x, y;
bool touched = getTouch(x, y);
if (touched) {
hapticFeedback();
this->setInterval(20);
_last_x = x;
_last_y = y;
}
if (touched != _touchedOld) {
if (touched) {
_state = TOUCH_EVENT_OCCURRED;
_start = millis();
_first_x = x;
_first_y = y;
} else {
_state = TOUCH_EVENT_CLEARED;
time_t duration = millis() - _start;
x = _last_x;
y = _last_y;
this->setInterval(50);
// compute distance
int16_t dx = x - _first_x;
int16_t dy = y - _first_y;
uint16_t adx = abs(dx);
uint16_t ady = abs(dy);
// swipe horizontal
if (adx > ady && adx > TOUCH_THRESHOLD_X) {
if (0 > dx) { // swipe right to left
e.touchEvent = static_cast<char>(TOUCH_ACTION_LEFT);
LOG_DEBUG("action SWIPE: right to left\n");
} else { // swipe left to right
e.touchEvent = static_cast<char>(TOUCH_ACTION_RIGHT);
LOG_DEBUG("action SWIPE: left to right\n");
}
}
// swipe vertical
else if (ady > adx && ady > TOUCH_THRESHOLD_Y) {
if (0 > dy) { // swipe bottom to top
e.touchEvent = static_cast<char>(TOUCH_ACTION_UP);
LOG_DEBUG("action SWIPE: bottom to top\n");
} else { // swipe top to bottom
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOWN);
LOG_DEBUG("action SWIPE: top to bottom\n");
}
}
// tap
else {
if (duration > 0 && duration < TIME_LONG_PRESS) {
if (_tapped) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOUBLE_TAP);
LOG_DEBUG("action DOUBLE TAP(%d/%d)\n", x, y);
} else {
_tapped = true;
}
} else {
_tapped = false;
}
}
}
}
_touchedOld = touched;
// fire TAP event when no 2nd tap occured within time
if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y);
}
// fire LONG_PRESS event without the need for release
if (touched && (time_t(millis()) - _start) > TIME_LONG_PRESS) {
// tricky: prevent reoccurring events and another touch event when releasing
_start = millis() + 30000;
e.touchEvent = static_cast<char>(TOUCH_ACTION_LONG_PRESS);
LOG_DEBUG("action LONG PRESS(%d/%d)\n", _last_x, _last_y);
}
if (e.touchEvent != TOUCH_ACTION_NONE) {
e.source = this->_originName;
e.x = _last_x;
e.y = _last_y;
onEvent(e);
}
return interval;
}
void TouchScreenBase::hapticFeedback()
{
#ifdef T_WATCH_S3
drv.setWaveform(0, 75);
drv.setWaveform(1, 0); // end waveform
drv.go();
#endif
}

View File

@@ -0,0 +1,55 @@
#pragma once
#include "InputBroker.h"
#include "concurrency/OSThread.h"
#include "mesh/NodeDB.h"
typedef struct _TouchEvent {
const char *source;
char touchEvent;
uint16_t x;
uint16_t y;
} TouchEvent;
class TouchScreenBase : public Observable<const InputEvent *>, public concurrency::OSThread
{
public:
explicit TouchScreenBase(const char *name, uint16_t width, uint16_t height);
void init(bool hasTouch);
protected:
enum TouchScreenBaseStateType { TOUCH_EVENT_OCCURRED, TOUCH_EVENT_CLEARED };
enum TouchScreenBaseEventType {
TOUCH_ACTION_NONE,
TOUCH_ACTION_UP,
TOUCH_ACTION_DOWN,
TOUCH_ACTION_LEFT,
TOUCH_ACTION_RIGHT,
TOUCH_ACTION_TAP,
TOUCH_ACTION_DOUBLE_TAP,
TOUCH_ACTION_LONG_PRESS
};
virtual int32_t runOnce() override;
virtual bool getTouch(int16_t &x, int16_t &y) = 0;
virtual void onEvent(const TouchEvent &event) = 0;
volatile TouchScreenBaseStateType _state = TOUCH_EVENT_CLEARED;
volatile TouchScreenBaseEventType _action = TOUCH_ACTION_NONE;
void hapticFeedback();
protected:
uint16_t _display_width;
uint16_t _display_height;
private:
bool _touchedOld = false; // previous touch state
int16_t _first_x, _last_x; // horizontal swipe direction
int16_t _first_y, _last_y; // vertical swipe direction
time_t _start; // for LONG_PRESS
bool _tapped; // for DOUBLE_TAP
const char *_originName;
};

View File

@@ -0,0 +1,68 @@
#include "TouchScreenImpl1.h"
#include "InputBroker.h"
#include "configuration.h"
TouchScreenImpl1 *touchScreenImpl1;
TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *))
: TouchScreenBase("touchscreen1", width, height), _getTouch(getTouch)
{
}
void TouchScreenImpl1::init()
{
#if !HAS_TOUCHSCREEN
TouchScreenBase::init(false);
return;
#else
TouchScreenBase::init(true);
inputBroker->registerSource(this);
#endif
}
bool TouchScreenImpl1::getTouch(int16_t &x, int16_t &y)
{
return _getTouch(&x, &y);
}
/**
* @brief forward touchscreen event
*
* @param event
*
* The touchscreen events are translated to input events and reversed
*/
void TouchScreenImpl1::onEvent(const TouchEvent &event)
{
InputEvent e;
e.source = event.source;
switch (event.touchEvent) {
case TOUCH_ACTION_LEFT: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
break;
}
case TOUCH_ACTION_RIGHT: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
break;
}
case TOUCH_ACTION_UP: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
break;
}
case TOUCH_ACTION_DOWN: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
break;
}
case TOUCH_ACTION_DOUBLE_TAP: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
break;
}
case TOUCH_ACTION_LONG_PRESS: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL);
break;
}
default:
return;
}
this->notifyObservers(&e);
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "TouchScreenBase.h"
class TouchScreenImpl1 : public TouchScreenBase
{
public:
TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *));
void init(void);
protected:
virtual bool getTouch(int16_t &x, int16_t &y);
virtual void onEvent(const TouchEvent &event);
bool (*_getTouch)(int16_t *, int16_t *);
};
extern TouchScreenImpl1 *touchScreenImpl1;

View File

@@ -0,0 +1,78 @@
#include "TrackballInterruptBase.h"
#include "configuration.h"
TrackballInterruptBase::TrackballInterruptBase(const char *name)
{
this->_originName = name;
}
void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress,
char eventDown, char eventUp, char eventLeft, char eventRight, char eventPressed,
void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(), void (*onIntRight)(),
void (*onIntPress)())
{
this->_pinDown = pinDown;
this->_pinUp = pinUp;
this->_pinLeft = pinLeft;
this->_pinRight = pinRight;
this->_eventDown = eventDown;
this->_eventUp = eventUp;
this->_eventLeft = eventLeft;
this->_eventRight = eventRight;
this->_eventPressed = eventPressed;
pinMode(pinPress, INPUT_PULLUP);
pinMode(this->_pinDown, INPUT_PULLUP);
pinMode(this->_pinUp, INPUT_PULLUP);
pinMode(this->_pinLeft, INPUT_PULLUP);
pinMode(this->_pinRight, INPUT_PULLUP);
attachInterrupt(pinPress, onIntPress, RISING);
attachInterrupt(this->_pinDown, onIntDown, RISING);
attachInterrupt(this->_pinUp, onIntUp, RISING);
attachInterrupt(this->_pinLeft, onIntLeft, RISING);
attachInterrupt(this->_pinRight, onIntRight, RISING);
LOG_DEBUG("Trackball GPIO initialized (%d, %d, %d, %d, %d)\n", this->_pinUp, this->_pinDown, this->_pinLeft, this->_pinRight,
pinPress);
}
void TrackballInterruptBase::intPressHandler()
{
InputEvent e;
e.source = this->_originName;
e.inputEvent = this->_eventPressed;
this->notifyObservers(&e);
}
void TrackballInterruptBase::intDownHandler()
{
InputEvent e;
e.source = this->_originName;
e.inputEvent = this->_eventDown;
this->notifyObservers(&e);
}
void TrackballInterruptBase::intUpHandler()
{
InputEvent e;
e.source = this->_originName;
e.inputEvent = this->_eventUp;
this->notifyObservers(&e);
}
void TrackballInterruptBase::intLeftHandler()
{
InputEvent e;
e.source = this->_originName;
e.inputEvent = this->_eventLeft;
this->notifyObservers(&e);
}
void TrackballInterruptBase::intRightHandler()
{
InputEvent e;
e.source = this->_originName;
e.inputEvent = this->_eventRight;
this->notifyObservers(&e);
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "InputBroker.h"
#include "mesh/NodeDB.h"
class TrackballInterruptBase : public Observable<const InputEvent *>
{
public:
explicit TrackballInterruptBase(const char *name);
void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress, char eventDown, char eventUp,
char eventLeft, char eventRight, char eventPressed, void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(),
void (*onIntRight)(), void (*onIntPress)());
void intPressHandler();
void intDownHandler();
void intUpHandler();
void intLeftHandler();
void intRightHandler();
private:
uint8_t _pinDown = 0;
uint8_t _pinUp = 0;
uint8_t _pinLeft = 0;
uint8_t _pinRight = 0;
char _eventDown = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventUp = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventLeft = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventRight = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
const char *_originName;
};

View File

@@ -0,0 +1,54 @@
#include "TrackballInterruptImpl1.h"
#include "InputBroker.h"
#include "configuration.h"
TrackballInterruptImpl1 *trackballInterruptImpl1;
TrackballInterruptImpl1::TrackballInterruptImpl1() : TrackballInterruptBase("trackball1") {}
void TrackballInterruptImpl1::init()
{
#if !HAS_TRACKBALL
// Input device is disabled.
return;
#else
uint8_t pinUp = TB_UP;
uint8_t pinDown = TB_DOWN;
uint8_t pinLeft = TB_LEFT;
uint8_t pinRight = TB_RIGHT;
uint8_t pinPress = TB_PRESS;
char eventDown = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
char eventUp = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
char eventLeft = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
char eventRight = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
char eventPressed = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
TrackballInterruptBase::init(pinDown, pinUp, pinLeft, pinRight, pinPress, eventDown, eventUp, eventLeft, eventRight,
eventPressed, TrackballInterruptImpl1::handleIntDown, TrackballInterruptImpl1::handleIntUp,
TrackballInterruptImpl1::handleIntLeft, TrackballInterruptImpl1::handleIntRight,
TrackballInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this);
#endif
}
void TrackballInterruptImpl1::handleIntDown()
{
trackballInterruptImpl1->intDownHandler();
}
void TrackballInterruptImpl1::handleIntUp()
{
trackballInterruptImpl1->intUpHandler();
}
void TrackballInterruptImpl1::handleIntLeft()
{
trackballInterruptImpl1->intLeftHandler();
}
void TrackballInterruptImpl1::handleIntRight()
{
trackballInterruptImpl1->intRightHandler();
}
void TrackballInterruptImpl1::handleIntPressed()
{
trackballInterruptImpl1->intPressHandler();
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "TrackballInterruptBase.h"
class TrackballInterruptImpl1 : public TrackballInterruptBase
{
public:
TrackballInterruptImpl1();
void init();
static void handleIntDown();
static void handleIntUp();
static void handleIntLeft();
static void handleIntRight();
static void handleIntPressed();
};
extern TrackballInterruptImpl1 *trackballInterruptImpl1;

View File

@@ -23,7 +23,7 @@ void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
attachInterrupt(this->_pinDown, onIntDown, RISING);
attachInterrupt(this->_pinUp, onIntUp, RISING);
LOG_DEBUG("GPIO initialized (%d, %d, %d)\n", this->_pinDown, this->_pinUp, pinPress);
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)\n", this->_pinUp, this->_pinDown, pinPress);
}
void UpDownInterruptBase::intPressHandler()

View File

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

View File

@@ -41,7 +41,7 @@ void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
int32_t KbI2cBase::runOnce()
{
if (cardkb_found.address != CARDKB_ADDR) {
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
// Input device is not detected.
return INT32_MAX;
}
@@ -85,9 +85,9 @@ int32_t KbI2cBase::runOnce()
e.kbchar = PrintDataBuf;
this->notifyObservers(&e);
}
} else {
// m5 cardkb
i2cBus->requestFrom(CARDKB_ADDR, 1);
} else if (kb_model == 0x00 || kb_model == 0x10) {
// m5 cardkb and T-Deck
i2cBus->requestFrom(kb_model == 0x00 ? CARDKB_ADDR : TDECK_KB_ADDR, 1);
while (i2cBus->available()) {
char c = i2cBus->read();
@@ -132,6 +132,8 @@ int32_t KbI2cBase::runOnce()
this->notifyObservers(&e);
}
}
} else {
LOG_WARN("Unknown kb_model 0x%02x\n", kb_model);
}
return 500;
return 300;
}

View File

@@ -19,6 +19,7 @@
#include "detect/ScanI2CTwoWire.h"
#include "detect/axpDebug.h"
#include "detect/einkScan.h"
#include "graphics/RAKled.h"
#include "graphics/Screen.h"
#include "main.h"
#include "mesh/generated/meshtastic/config.pb.h"
@@ -46,19 +47,21 @@ NRF52Bluetooth *nrf52Bluetooth;
#if HAS_WIFI
#include "mesh/api/WiFiServerAPI.h"
#include "mqtt/MQTT.h"
#endif
#if HAS_ETHERNET
#include "mesh/api/ethServerAPI.h"
#include "mqtt/MQTT.h"
#endif
#include "mqtt/MQTT.h"
#include "LLCC68Interface.h"
#include "RF95Interface.h"
#include "SX1262Interface.h"
#include "SX1268Interface.h"
#include "SX1280Interface.h"
#ifdef ARCH_STM32WL
#include "STM32WLE5JCInterface.h"
#endif
#if !HAS_RADIO && defined(ARCH_PORTDUINO)
#include "platform/portduino/SimRadio.h"
#endif
@@ -68,7 +71,7 @@ NRF52Bluetooth *nrf52Bluetooth;
#endif
#include "PowerFSMThread.h"
#if !defined(ARCH_PORTDUINO)
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "AccelerometerThread.h"
#endif
@@ -93,18 +96,25 @@ ScanI2C::DeviceAddress screen_found = ScanI2C::ADDRESS_NONE;
// The I2C address of the cardkb or RAK14004 (if found)
ScanI2C::DeviceAddress cardkb_found = ScanI2C::ADDRESS_NONE;
// 0x02 for RAK14004 and 0x00 for cardkb
// 0x02 for RAK14004, 0x00 for cardkb, 0x10 for T-Deck
uint8_t kb_model;
// The I2C address of the RTC Module (if found)
ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE;
// The I2C address of the Accelerometer (if found)
ScanI2C::DeviceAddress accelerometer_found = ScanI2C::ADDRESS_NONE;
// The I2C address of the RGB LED (if found)
ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ScanI2C::ADDRESS_NONE);
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
ATECCX08A atecc;
#endif
#ifdef T_WATCH_S3
Adafruit_DRV2605 drv;
#endif
bool isVibrating = false;
bool eink_found = true;
uint32_t serialSinceMsec;
@@ -159,11 +169,12 @@ static OSThread *buttonThread;
uint32_t ButtonThread::longPressTime = 0;
#endif
static OSThread *accelerometerThread;
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
RadioInterface *rIf = NULL;
/**
* Some platforms (nrf52) might provide an alterate version that supresses calling delay from sleep.
* Some platforms (nrf52) might provide an alterate version that suppresses calling delay from sleep.
*/
__attribute__((weak, noinline)) bool loopCanSleep()
{
@@ -208,6 +219,16 @@ void setup()
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
#endif
#ifdef VGNSS_CTRL
pinMode(VGNSS_CTRL, OUTPUT);
digitalWrite(VGNSS_CTRL, LOW);
#endif
#if defined(VTFT_CTRL)
pinMode(VTFT_CTRL, OUTPUT);
digitalWrite(VTFT_CTRL, LOW);
#endif
#ifdef RESET_OLED
pinMode(RESET_OLED, OUTPUT);
digitalWrite(RESET_OLED, 1);
@@ -234,7 +255,18 @@ void setup()
fsInit();
router = new ReliableRouter();
#if defined(_SEEED_XIAO_NRF52840_SENSE_H_)
pinMode(CHARGE_LED, INPUT); // sets to detect if charge LED is on or off to see if USB is plugged in
pinMode(HICHG, OUTPUT);
digitalWrite(HICHG, LOW); // 100 mA charging current if set to LOW and 50mA (actually about 20mA) if set to HIGH
pinMode(BAT_READ, OUTPUT);
digitalWrite(BAT_READ, LOW); // This is pin P0_14 = 14 and by pullling low to GND it provices path to read on pin 32 (P0,31)
// PIN_VBAT the voltage from divider on XIAO board
#endif
#ifdef I2C_SDA1
Wire1.begin(I2C_SDA1, I2C_SCL1);
@@ -256,10 +288,26 @@ void setup()
#endif
#ifdef RAK4630
#ifdef PIN_3V3_EN
// We need to enable 3.3V periphery in order to scan it
pinMode(PIN_3V3_EN, OUTPUT);
digitalWrite(PIN_3V3_EN, HIGH);
#endif
#ifndef USE_EINK
// RAK-12039 set pin for Air quality sensor
pinMode(AQ_SET_PIN, OUTPUT);
digitalWrite(AQ_SET_PIN, HIGH);
#endif
#endif
#ifdef T_DECK
// enable keyboard
pinMode(KB_POWERON, OUTPUT);
digitalWrite(KB_POWERON, HIGH);
// There needs to be a delay after power on, give LILYGO-KEYBOARD some startup time
// otherwise keyboard and touch screen will not work
delay(800);
#endif
// Currently only the tbeam has a PMU
// PMU initialization needs to be placed before i2c scanning
@@ -333,21 +381,41 @@ void setup()
kb_model = 0x02;
break;
case ScanI2C::DeviceType::CARDKB:
kb_model = 0x00;
break;
case ScanI2C::DeviceType::TDECKKB:
// assign an arbitrary value to distinguish from other models
kb_model = 0x10;
break;
default:
// use this as default since it's also just zero
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type);
kb_model = 0x00;
}
}
pmu_found = i2cScanner->exists(ScanI2C::DeviceType::PMU_AXP192_AXP2101);
/*
* There are a bunch of sensors that have no further logic than to be found and stuffed into the
* nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field
* "found".
*/
/*
* There are a bunch of sensors that have no further logic than to be found and stuffed into the
* nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field
* "found".
*/
#if !defined(ARCH_PORTDUINO)
// Only one supported RGB LED currently
#ifdef HAS_NCP5623
rgb_found = i2cScanner->find(ScanI2C::DeviceType::NCP5623);
// Start the RGB LED at 50%
if (rgb_found.type == ScanI2C::NCP5623) {
rgb.begin();
rgb.setCurrent(10);
rgb.setColor(128, 128, 128);
}
#endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
auto acc_info = i2cScanner->firstAccelerometer();
accelerometer_found = acc_info.type != ScanI2C::DeviceType::NONE ? acc_info.address : accelerometer_found;
LOG_DEBUG("acc_info = %i\n", acc_info.type);
@@ -406,6 +474,11 @@ void setup()
#ifdef ARCH_NRF52
nrf52Setup();
#endif
#ifdef ARCH_RP2040
rp2040Setup();
#endif
// We do this as early as possible because this loads preferences from flash
// but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
nodeDB.init();
@@ -413,6 +486,8 @@ void setup()
// If we're taking on the repeater role, use flood router
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
router = new FloodingRouter();
else
router = new ReliableRouter();
#if HAS_BUTTON
// Buttons. Moved here cause we need NodeDB to be initialized
@@ -434,15 +509,38 @@ void setup()
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // keep dimension of 128x64
#endif
#if !defined(ARCH_PORTDUINO)
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
if (acc_info.type != ScanI2C::DeviceType::NONE) {
config.display.wake_on_tap_or_motion = true;
moduleConfig.external_notification.enabled = true;
accelerometerThread = new AccelerometerThread(acc_info.type);
}
#endif
#ifdef T_WATCH_S3
drv.begin();
drv.selectLibrary(1);
// I2C trigger by sending 'go' command
drv.setMode(DRV2605_MODE_INTTRIG);
#endif
// Init our SPI controller (must be before screen and lora)
initSPI();
#ifndef ARCH_ESP32
#ifdef ARCH_RP2040
#ifdef HW_SPI1_DEVICE
SPI1.setSCK(RF95_SCK);
SPI1.setTX(RF95_MOSI);
SPI1.setRX(RF95_MISO);
pinMode(RF95_NSS, OUTPUT);
digitalWrite(RF95_NSS, HIGH);
SPI1.begin(false);
#else // HW_SPI1_DEVICE
SPI.setSCK(RF95_SCK);
SPI.setTX(RF95_MOSI);
SPI.setRX(RF95_MISO);
SPI.begin(false);
#endif // HW_SPI1_DEVICE
#elif !defined(ARCH_ESP32) // ARCH_RP2040
SPI.begin();
#else
// ESP32
@@ -457,10 +555,11 @@ void setup()
gps = createGps();
if (gps)
if (gps) {
gpsStatus->observe(&gps->newStatus);
else
} else {
LOG_WARN("No GPS found - running without GPS\n");
}
nodeStatus->observe(&nodeDB.newStatus);
@@ -477,7 +576,7 @@ void setup()
// Don't call screen setup until after nodedb is setup (because we need
// the current region name)
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER)
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
screen->setup();
#else
if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
@@ -503,7 +602,25 @@ void setup()
digitalWrite(SX126X_ANT_SW, 1);
#endif
#ifdef HW_SPI1_DEVICE
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
#else // HW_SPI1_DEVICE
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
#endif
// radio init MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
#if defined(USE_STM32WLx)
if (!rIf) {
rIf = new STM32WLE5JCInterface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find STM32WL radio\n");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("STM32WL Radio init succeeded, using STM32WL radio\n");
}
}
#endif
#if !HAS_RADIO && defined(ARCH_PORTDUINO)
if (!rIf) {
@@ -520,7 +637,7 @@ void setup()
#if defined(RF95_IRQ)
if (!rIf) {
rIf = new RF95Interface(RF95_NSS, RF95_IRQ, RF95_RESET, RF95_DIO1, SPI);
rIf = new RF95Interface(RadioLibHAL, RF95_NSS, RF95_IRQ, RF95_RESET, RF95_DIO1);
if (!rIf->init()) {
LOG_WARN("Failed to find RF95 radio\n");
delete rIf;
@@ -533,7 +650,7 @@ void setup()
#if defined(USE_SX1262)
if (!rIf) {
rIf = new SX1262Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find SX1262 radio\n");
delete rIf;
@@ -546,7 +663,7 @@ void setup()
#if defined(USE_SX1268)
if (!rIf) {
rIf = new SX1268Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
rIf = new SX1268Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find SX1268 radio\n");
delete rIf;
@@ -559,7 +676,7 @@ void setup()
#if defined(USE_LLCC68)
if (!rIf) {
rIf = new LLCC68Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
rIf = new LLCC68Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find LLCC68 radio\n");
delete rIf;
@@ -572,7 +689,7 @@ void setup()
#if defined(USE_SX1280)
if (!rIf) {
rIf = new SX1280Interface(SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY, SPI);
rIf = new SX1280Interface(RadioLibHAL, SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY);
if (!rIf->init()) {
LOG_WARN("Failed to find SX1280 radio\n");
delete rIf;
@@ -596,9 +713,7 @@ void setup()
}
}
#if HAS_WIFI || HAS_ETHERNET
mqttInit();
#endif
#ifndef ARCH_PORTDUINO
// Initialize Wifi
@@ -625,12 +740,10 @@ void setup()
else {
router->addInterface(rIf);
// Calculate and save the bit rate to myNodeInfo
// TODO: This needs to be added what ever method changes the channel from the phone.
myNodeInfo.bitrate =
(float(meshtastic_Constants_DATA_PAYLOAD_LEN) / (float(rIf->getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN)))) *
1000;
LOG_DEBUG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
// Log bit rate to debug output
LOG_DEBUG("LoRA bitrate = %f bytes / sec\n", (float(meshtastic_Constants_DATA_PAYLOAD_LEN) /
(float(rIf->getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN)))) *
1000);
}
// This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values
@@ -645,13 +758,13 @@ uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reb
uint32_t shutdownAtMsec; // If not zero we will shutdown at this time (used to shutdown from python or mobile client)
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
// This will supress the current delay and instead try to run ASAP.
// This will suppress the current delay and instead try to run ASAP.
bool runASAP;
extern meshtastic_DeviceMetadata getDeviceMetadata()
{
meshtastic_DeviceMetadata deviceMetadata;
strncpy(deviceMetadata.firmware_version, myNodeInfo.firmware_version, 18);
strncpy(deviceMetadata.firmware_version, optstr(APP_VERSION), sizeof(deviceMetadata.firmware_version));
deviceMetadata.device_state_version = DEVICESTATE_CUR_VER;
deviceMetadata.canShutdown = pmu_found || HAS_CPU_SHUTDOWN;
deviceMetadata.hasBluetooth = HAS_BLUETOOTH;
@@ -660,6 +773,7 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
deviceMetadata.role = config.device.role;
deviceMetadata.position_flags = config.position.position_flags;
deviceMetadata.hw_model = HW_VENDOR;
deviceMetadata.hasRemoteHardware = moduleConfig.remote_hardware.enabled;
return deviceMetadata;
}
@@ -707,4 +821,4 @@ void loop()
mainDelay.delay(delayMsec);
}
// if (didWake) LOG_DEBUG("wake!\n");
}
}

View File

@@ -8,6 +8,7 @@
#include "memGet.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include "mesh/generated/meshtastic/telemetry.pb.h"
#include <SPI.h>
#include <map>
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include <SparkFun_ATECCX08a_Arduino_Library.h>
@@ -26,6 +27,7 @@ extern ScanI2C::DeviceAddress cardkb_found;
extern uint8_t kb_model;
extern ScanI2C::DeviceAddress rtc_found;
extern ScanI2C::DeviceAddress accelerometer_found;
extern ScanI2C::FoundDevice rgb_found;
extern bool eink_found;
extern bool pmu_found;
@@ -36,7 +38,11 @@ extern bool isUSBPowered;
extern ATECCX08A atecc;
#endif
extern uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1];
#ifdef T_WATCH_S3
#include <Adafruit_DRV2605.h>
extern Adafruit_DRV2605 drv;
#endif
extern bool isVibrating;
extern int TCPPort; // set by Portduino
@@ -59,9 +65,12 @@ extern uint32_t shutdownAtMsec;
extern uint32_t serialSinceMsec;
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
// This will supress the current delay and instead try to run ASAP.
// This will suppress the current delay and instead try to run ASAP.
extern bool runASAP;
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), clearBonds();
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds();
meshtastic_DeviceMetadata getDeviceMetadata();
// FIXME, we default to 4MHz SPI, SPI mode 0, check if the datasheet says it can really do that
extern SPISettings spiSettings;

View File

@@ -108,8 +108,9 @@ CryptoKey Channels::getKey(ChannelIndex chIndex)
if (ch.role == meshtastic_Channel_Role_SECONDARY) {
LOG_DEBUG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name);
k = getKey(primaryIndex);
} else
} else {
LOG_WARN("User disabled encryption\n");
}
} else if (k.length == 1) {
// Convert the short single byte variants of psk into variant that can be used more generally

View File

@@ -20,7 +20,7 @@ class Channels
/// The index of the primary channel
ChannelIndex primaryIndex = 0;
/** The channel index that was requested for sending/receving. Note: if this channel is a secondary
/** The channel index that was requested for sending/receiving. Note: if this channel is a secondary
channel and does not have a PSK, we will use the PSK from the primary channel. If this channel is disabled
no sending or receiving will be allowed */
ChannelIndex activeChannelIndex = 0;

View File

@@ -21,6 +21,12 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
{
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
printPacket("Ignoring incoming msg, because we've already seen it", p);
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT &&
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
// cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater!
Router::cancelSending(p->from, p->id);
}
return true;
}
@@ -62,4 +68,4 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
}
// handle the packet as normal
Router::sniffReceived(p, c);
}
}

View File

@@ -48,7 +48,7 @@ class FloodingRouter : public Router, protected PacketHistory
/**
* Should this incoming filter be dropped?
*
* Called immedately on receiption, before any further processing.
* Called immediately on reception, before any further processing.
* @return true to abandon the packet
*/
virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override;

View File

@@ -10,6 +10,9 @@ template class SX126xInterface<SX1262>;
template class SX126xInterface<SX1268>;
template class SX126xInterface<LLCC68>;
template class SX128xInterface<SX1280>;
#ifdef ARCH_STM32WL
template class SX126xInterface<STM32WLx>;
#endif
#if HAS_ETHERNET
#include "api/ethServerAPI.h"

View File

@@ -2,8 +2,8 @@
#include "configuration.h"
#include "error.h"
LLCC68Interface::LLCC68Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
SPIClass &spi)
: SX126xInterface(cs, irq, rst, busy, spi)
LLCC68Interface::LLCC68Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
RADIOLIB_PIN_TYPE busy)
: SX126xInterface(hal, cs, irq, rst, busy)
{
}

View File

@@ -6,12 +6,13 @@
* Our adapter for LLCC68 radios
* https://www.semtech.com/products/wireless-rf/lora-core/llcc68
* ⚠️⚠️⚠️
* Be aware that LLCC68 does not support Spreading Factor 12 (SF12) and will not work on the default "Long Slow" channel.
* Be aware that LLCC68 does not support Spreading Factor 12 (SF12) and will not work on the "LongSlow" and "VLongSlow" channels.
* You must change the channel if you get `Critical Error #3` with this module.
* ⚠️⚠️⚠️
*/
class LLCC68Interface : public SX126xInterface<LLCC68>
{
public:
LLCC68Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
LLCC68Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
RADIOLIB_PIN_TYPE busy);
};

View File

@@ -18,7 +18,7 @@ meshtastic_MeshPacket *MeshModule::currentReply;
MeshModule::MeshModule(const char *_name) : name(_name)
{
// Can't trust static initalizer order, so we check each time
// Can't trust static initializer order, so we check each time
if (!modules)
modules = new std::vector<MeshModule *>();
@@ -39,7 +39,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
c.error_reason = err;
c.which_variant = meshtastic_Routing_error_reason_tag;
// Now that we have moded sendAckNak up one level into the class heirarchy we can no longer assume we are a RoutingPlugin
// Now that we have moded sendAckNak up one level into the class hierarchy we can no longer assume we are a RoutingPlugin
// So we manually call pb_encode_to_bytes and specify routing port number
// auto p = allocDataProtobuf(c);
meshtastic_MeshPacket *p = router->allocForSending();
@@ -169,7 +169,7 @@ void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src)
// Note: if the message started with the local node or a module asked to ignore the request, we don't want to send a
// no response reply
// No one wanted to reply to this requst, tell the requster that happened
// No one wanted to reply to this request, tell the requster that happened
LOG_DEBUG("No one responded, send a nak\n");
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
@@ -179,9 +179,10 @@ void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src)
}
}
if (!moduleFound)
if (!moduleFound) {
LOG_DEBUG("No modules interested in portnum=%d, src=%s\n", mp.decoded.portnum,
(src == RX_SRC_LOCAL) ? "LOCAL" : "REMOTE");
}
}
meshtastic_MeshPacket *MeshModule::allocReply()

View File

@@ -47,7 +47,7 @@ typedef struct _UIFrameEvent {
* A key concept for this is that your module should use a particular "portnum" for each message type you want to receive
* and handle.
*
* Interally we use modules to implement the core meshtastic text messaging and gps position sharing features. You
* Internally we use modules to implement the core meshtastic text messaging and gps position sharing features. You
* can use these classes as examples for how to write your own custom module. See here: (FIXME)
*/
class MeshModule

View File

@@ -9,6 +9,7 @@
#include "NodeDB.h"
#include "PowerFSM.h"
#include "RTC.h"
#include "TypeConversions.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "modules/NodeInfoModule.h"
@@ -33,7 +34,7 @@ arbitrating to select a node number and keeping the current nodedb.
/* Broadcast when a newly powered mesh node wants to find a node num it can use
The algoritm is as follows:
The algorithm is as follows:
* when a node starts up, it broadcasts their user and the normal flow is for all other nodes to reply with their User as well (so
the new node can build its node db)
* If a node ever receives a User (not just the first broadcast) message where the sender node number equals our node number, that
@@ -51,13 +52,18 @@ FIXME in the initial proof of concept we just skip the entire want/deny flow and
MeshService service;
static MemoryDynamic<meshtastic_MqttClientProxyMessage> staticMqttClientProxyMessagePool;
static MemoryDynamic<meshtastic_QueueStatus> staticQueueStatusPool;
Allocator<meshtastic_MqttClientProxyMessage> &mqttClientProxyMessagePool = staticMqttClientProxyMessagePool;
Allocator<meshtastic_QueueStatus> &queueStatusPool = staticQueueStatusPool;
#include "Router.h"
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE)
MeshService::MeshService()
: toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE), toPhoneMqttProxyQueue(MAX_RX_TOPHONE)
{
lastQueueStatus = {0, 0, 16, 0};
}
@@ -76,7 +82,13 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB.getNode(mp->from)->has_user && nodeInfoModule) {
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag &&
mp->decoded.portnum == meshtastic_PortNum_TELEMETRY_APP && mp->decoded.request_id > 0) {
LOG_DEBUG(
"Received telemetry response. Skip sending our NodeInfo because this potentially a Repeater which will ignore our "
"request for its NodeInfo.\n");
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB.getMeshNode(mp->from)->has_user &&
nodeInfoModule) {
LOG_INFO("Heard a node on channel %d we don't know, sending NodeInfo and asking for a response.\n", mp->channel);
nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel);
}
@@ -236,10 +248,11 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
{
meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
assert(node);
if (node->has_position && (node->position.latitude_i != 0 || node->position.longitude_i != 0)) {
if (hasValidPosition(node)) {
if (positionModule) {
LOG_INFO("Sending position ping to 0x%x, wantReplies=%d, channel=%d\n", dest, wantReplies, node->channel);
positionModule->sendOurPosition(dest, wantReplies, node->channel);
@@ -266,9 +279,23 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p)
fromNum++;
}
meshtastic_NodeInfo *MeshService::refreshMyNodeInfo()
void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m)
{
meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
LOG_DEBUG("Sending mqtt message on topic '%s' to client for proxying to server\n", m->topic);
if (toPhoneMqttProxyQueue.numFree() == 0) {
LOG_WARN("MqttClientProxyMessagePool queue is full, discarding oldest\n");
meshtastic_MqttClientProxyMessage *d = toPhoneMqttProxyQueue.dequeuePtr(0);
if (d)
releaseMqttClientProxyMessageToPool(d);
}
assert(toPhoneMqttProxyQueue.enqueue(m, 0));
fromNum++;
}
meshtastic_NodeInfoLite *MeshService::refreshLocalMeshNode()
{
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
assert(node);
// We might not have a position yet for our local node, in that case, at least try to send the time
@@ -277,7 +304,7 @@ meshtastic_NodeInfo *MeshService::refreshMyNodeInfo()
node->has_position = true;
}
meshtastic_Position &position = node->position;
meshtastic_PositionLite &position = node->position;
// Update our local node info with our time (even if we don't decide to update anyone else)
node->last_heard =
@@ -293,7 +320,7 @@ meshtastic_NodeInfo *MeshService::refreshMyNodeInfo()
int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
{
// Update our local node info with our position (even if we don't decide to update anyone else)
meshtastic_NodeInfo *node = refreshMyNodeInfo();
meshtastic_NodeInfoLite *node = refreshLocalMeshNode();
meshtastic_Position pos = meshtastic_Position_init_default;
if (newStatus->getHasLock()) {
@@ -307,12 +334,12 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
#endif
if (config.position.fixed_position) {
LOG_WARN("Using fixed position\n");
pos = node->position;
pos = ConvertToPosition(node->position);
}
}
// Finally add a fresh timestamp and battery level reading
// I KNOW this is redundant with refreshMyNodeInfo() above, but these are
// I KNOW this is redundant with refreshLocalMeshNode() above, but these are
// inexpensive nonblocking calls and can be refactored in due course
pos.time = getValidTime(RTCQualityGPS);
@@ -329,4 +356,4 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
bool MeshService::isToPhoneQueueEmpty()
{
return toPhoneQueue.isEmpty();
}
}

View File

@@ -15,6 +15,7 @@
#endif
extern Allocator<meshtastic_QueueStatus> &queueStatusPool;
extern Allocator<meshtastic_MqttClientProxyMessage> &mqttClientProxyMessagePool;
/**
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
@@ -34,6 +35,9 @@ class MeshService
// keep list of QueueStatus packets to be send to the phone
PointerQueue<meshtastic_QueueStatus> toPhoneQueueStatusQueue;
// keep list of MqttClientProxyMessages to be send to the client for delivery
PointerQueue<meshtastic_MqttClientProxyMessage> toPhoneMqttProxyQueue;
// This holds the last QueueStatus send
meshtastic_QueueStatus lastQueueStatus;
@@ -67,9 +71,15 @@ class MeshService
/// Return the next QueueStatus packet destined to the phone.
meshtastic_QueueStatus *getQueueStatusForPhone() { return toPhoneQueueStatusQueue.dequeuePtr(0); }
/// Return the next MqttClientProxyMessage packet destined to the phone.
meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); }
// Release QueueStatus packet to pool
void releaseQueueStatusToPool(meshtastic_QueueStatus *p) { queueStatusPool.release(p); }
// Release MqttClientProxyMessage packet to pool
void releaseMqttClientProxyMessageToPool(meshtastic_MqttClientProxyMessage *p) { mqttClientProxyMessagePool.release(p); }
/**
* 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
@@ -98,16 +108,19 @@ class MeshService
bool cancelSending(PacketId id);
/// Pull the latest power and time info into my nodeinfo
meshtastic_NodeInfo *refreshMyNodeInfo();
meshtastic_NodeInfoLite *refreshLocalMeshNode();
/// Send a packet to the phone
void sendToPhone(meshtastic_MeshPacket *p);
/// Send an MQTT message to the phone for client proxying
void sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m);
bool isToPhoneQueueEmpty();
private:
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
/// returns 0 to allow futher processing
/// returns 0 to allow further processing
int onGPSChanged(const meshtastic::GPSStatus *arg);
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
@@ -118,4 +131,4 @@ class MeshService
ErrorCode sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id);
};
extern MeshService service;
extern MeshService service;

View File

@@ -13,7 +13,7 @@ typedef uint32_t PacketId; // A packet sequence number
#define ERRNO_OK 0
#define ERRNO_NO_INTERFACES 33
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
#define ERRNO_DISABLED 34 // the itnerface is disabled
#define ERRNO_DISABLED 34 // the interface is disabled
/*
* Source of a received message

View File

@@ -11,6 +11,7 @@
#include "PowerFSM.h"
#include "RTC.h"
#include "Router.h"
#include "TypeConversions.h"
#include "error.h"
#include "main.h"
#include "mesh-pb-constants.h"
@@ -55,10 +56,18 @@ extern void getMacAddr(uint8_t *dmac);
* we use !macaddr (no colons).
*/
meshtastic_User &owner = devicestate.owner;
meshtastic_Position localPosition = meshtastic_Position_init_default;
meshtastic_CriticalErrorCode error_code =
meshtastic_CriticalErrorCode_NONE; // For the error code, only show values from this boot (discard value from flash)
uint32_t error_address = 0;
static uint8_t ourMacAddr[6];
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
NodeDB::NodeDB()
: nodes(devicestate.node_db), numNodes(&devicestate.node_db_count), meshNodes(devicestate.node_db_lite),
numMeshNodes(&devicestate.node_db_lite_count)
{
}
/**
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on
@@ -129,7 +138,7 @@ bool NodeDB::factoryReset()
// third, write everything to disk
saveToDisk();
#ifdef ARCH_ESP32
// This will erase what's in NVS including ssl keys, persistant variables and ble pairing
// This will erase what's in NVS including ssl keys, persistent variables and ble pairing
nvs_flash_erase();
#endif
#ifdef ARCH_NRF52
@@ -156,7 +165,8 @@ void NodeDB::installDefaultConfig()
config.has_network = true;
config.has_bluetooth = true;
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_ALL;
config.lora.sx126x_rx_boosted_gain = false;
config.lora.sx126x_rx_boosted_gain = true;
config.lora.tx_enabled =
true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off)
config.lora.override_duty_cycle = false;
@@ -175,7 +185,7 @@ void NodeDB::installDefaultConfig()
// FIXME: Default to bluetooth capability of platform as default
config.bluetooth.enabled = true;
config.bluetooth.fixed_pin = defaultBLEPin;
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER)
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
bool hasScreen = true;
#else
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
@@ -186,6 +196,11 @@ void NodeDB::installDefaultConfig()
config.position.position_flags =
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL);
#ifdef T_WATCH_S3
config.display.screen_on_secs = 30;
config.display.wake_on_tap_or_motion = true;
#endif
initConfigIntervals();
}
@@ -216,6 +231,19 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.has_store_forward = true;
moduleConfig.has_telemetry = true;
moduleConfig.has_external_notification = true;
#if defined(RAK4630) || defined(RAK11310)
// Default to RAK led pin 2 (blue)
moduleConfig.external_notification.enabled = true;
moduleConfig.external_notification.output = PIN_LED2;
moduleConfig.external_notification.active = true;
moduleConfig.external_notification.alert_message = true;
moduleConfig.external_notification.output_ms = 1000;
moduleConfig.external_notification.nag_timeout = 60;
#endif
#ifdef T_WATCH_S3
// Don't worry about the other settings, we'll use the DRV2056 behavior for notifications
moduleConfig.external_notification.enabled = true;
#endif
moduleConfig.has_canned_message = true;
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(moduleConfig.mqtt.address));
@@ -258,6 +286,9 @@ void NodeDB::resetNodes()
{
devicestate.node_db_count = 0;
memset(devicestate.node_db, 0, sizeof(devicestate.node_db));
devicestate.node_db_lite_count = 0;
memset(devicestate.node_db_lite, 0, sizeof(devicestate.node_db_lite));
saveDeviceStateToDisk();
}
@@ -272,17 +303,12 @@ void NodeDB::installDefaultDeviceState()
devicestate.has_my_node = true;
devicestate.has_owner = true;
devicestate.node_db_count = 0;
devicestate.node_db_lite_count = 0;
devicestate.version = DEVICESTATE_CUR_VER;
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
// default to no GPS, until one has been found by probing
myNodeInfo.has_gps = false;
myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME;
generatePacketId(); // FIXME - ugly way to init current_packet_id;
// Init our blank owner info to reasonable defaults
getMacAddr(ourMacAddr);
// Set default owner name
pickNewNodeNum(); // based on macaddr now
snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %02x%02x", ourMacAddr[4], ourMacAddr[5]);
@@ -303,28 +329,34 @@ void NodeDB::init()
int saveWhat = 0;
myNodeInfo.max_channels = MAX_NUM_CHANNELS; // tell others the max # of channels we can understand
myNodeInfo.error_code =
meshtastic_CriticalErrorCode_NONE; // For the error code, only show values from this boot (discard value from flash)
myNodeInfo.error_address = 0;
// likewise - we always want the app requirements to come from the running appload
myNodeInfo.min_app_version = 20300; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
myNodeInfo.min_app_version = 20300; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
myNodeInfo.max_channels = MAX_NUM_CHANNELS; // tell others the max # of channels we can understand
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
pickNewNodeNum();
// Set our board type so we can share it with others
owner.hw_model = HW_VENDOR;
// Include our owner in the node db under our nodenum
meshtastic_NodeInfo *info = getOrCreateNode(getNodeNum());
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
info->user = owner;
info->has_user = true;
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
if (*numNodes > 0) {
LOG_DEBUG("Legacy NodeDB detected... Migrating to NodeDBLite\n");
uint32_t readIndex = 0;
const meshtastic_NodeInfo *oldNodeInfo = nodeDB.readNextNodeInfo(readIndex);
while (oldNodeInfo != NULL) {
migrateToNodeInfoLite(oldNodeInfo);
oldNodeInfo = nodeDB.readNextNodeInfo(readIndex);
}
LOG_DEBUG("Migration complete! Clearing out legacy NodeDB...\n");
devicestate.node_db_count = 0;
memset(devicestate.node_db, 0, sizeof(devicestate.node_db));
}
#ifdef ARCH_ESP32
Preferences preferences;
@@ -332,11 +364,6 @@ void NodeDB::init()
myNodeInfo.reboot_count = preferences.getUInt("rebootCounter", 0);
preferences.end();
LOG_DEBUG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
/* The ESP32 has a wifi radio. This will need to be modified at some point so
* the test isn't so simplistic.
*/
myNodeInfo.has_wifi = true;
#endif
resetRadioConfig(); // If bogus settings got saved, then fix them
@@ -349,6 +376,11 @@ void NodeDB::init()
if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile)))
saveWhat |= SEGMENT_CHANNELS;
if (!devicestate.node_remote_hardware_pins) {
meshtastic_NodeRemoteHardwarePin empty[12] = {meshtastic_RemoteHardwarePin_init_default};
memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty));
}
saveToDisk(saveWhat);
}
@@ -362,17 +394,19 @@ void NodeDB::pickNewNodeNum()
{
NodeNum r = myNodeInfo.my_node_num;
// If we don't have a nodenum at app - pick an initial nodenum based on the macaddr
if (r == 0)
r = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
// Pick an initial nodenum based on the macaddr
r = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
if (r == NODENUM_BROADCAST || r < NUM_RESERVED)
r = NUM_RESERVED; // don't pick a reserved node number
meshtastic_NodeInfo *found;
while ((found = getNode(r)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr))) {
meshtastic_NodeInfoLite *found;
while ((found = getMeshNode(r)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr))) {
// FIXME: input for random() is int, so NODENUM_BROADCAST becomes -1
NodeNum n = random(NUM_RESERVED, NODENUM_BROADCAST); // try a new random choice
LOG_DEBUG("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 in use, so trying for 0x%x\n", r, n);
r = n;
}
@@ -468,8 +502,9 @@ void NodeDB::loadFromDisk()
}
}
if (loadProto(oemConfigFile, meshtastic_OEMStore_size, sizeof(meshtastic_OEMStore), &meshtastic_OEMStore_msg, &oemStore))
if (loadProto(oemConfigFile, meshtastic_OEMStore_size, sizeof(meshtastic_OEMStore), &meshtastic_OEMStore_msg, &oemStore)) {
LOG_INFO("Loaded OEMStore\n");
}
}
/** Save a protobuf from a file, return true for success */
@@ -494,10 +529,12 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
f.close();
// brief window of risk here ;-)
if (FSCom.exists(filename) && !FSCom.remove(filename))
if (FSCom.exists(filename) && !FSCom.remove(filename)) {
LOG_WARN("Can't remove old pref file\n");
if (!renameFile(filenameTmp.c_str(), filename))
}
if (!renameFile(filenameTmp.c_str(), filename)) {
LOG_ERROR("Error: can't rename new pref file\n");
}
} else {
LOG_ERROR("Can't write prefs\n");
#ifdef ARCH_NRF52
@@ -576,16 +613,24 @@ void NodeDB::saveToDisk(int saveWhat)
}
}
const meshtastic_NodeInfo *NodeDB::readNextInfo()
const meshtastic_NodeInfo *NodeDB::readNextNodeInfo(uint32_t &readIndex)
{
if (readPointer < *numNodes)
return &nodes[readPointer++];
if (readIndex < *numNodes)
return &nodes[readIndex++];
else
return NULL;
}
const meshtastic_NodeInfoLite *NodeDB::readNextMeshNode(uint32_t &readIndex)
{
if (readIndex < *numMeshNodes)
return &meshNodes[readIndex++];
else
return NULL;
}
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
uint32_t sinceLastSeen(const meshtastic_NodeInfo *n)
uint32_t sinceLastSeen(const meshtastic_NodeInfoLite *n)
{
uint32_t now = getTime();
@@ -609,13 +654,13 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p)
#define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline
size_t NodeDB::getNumOnlineNodes()
size_t NodeDB::getNumOnlineMeshNodes()
{
size_t numseen = 0;
// FIXME this implementation is kinda expensive
for (int i = 0; i < *numNodes; i++)
if (sinceLastSeen(&nodes[i]) < NUM_ONLINE_SECS)
for (int i = 0; i < *numMeshNodes; i++)
if (sinceLastSeen(&meshNodes[i]) < NUM_ONLINE_SECS)
numseen++;
return numseen;
@@ -627,7 +672,7 @@ size_t NodeDB::getNumOnlineNodes()
*/
void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSource src)
{
meshtastic_NodeInfo *info = getOrCreateNode(nodeId);
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId);
if (!info) {
return;
}
@@ -636,7 +681,9 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
// Local packet, fully authoritative
LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i,
p.longitude_i, p.altitude);
info->position = p;
info->position = ConvertToPositionLite(p);
localPosition = p;
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) {
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
// (stop-gap fix for issue #900)
@@ -654,7 +701,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
uint32_t tmp_time = info->position.time;
// Next, update atomically
info->position = p;
info->position = ConvertToPositionLite(p);
// Last, restore any fields that may have been overwritten
if (!info->position.time)
@@ -670,7 +717,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
*/
void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxSource src)
{
meshtastic_NodeInfo *info = getOrCreateNode(nodeId);
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId);
// Environment metrics should never go to NodeDb but we'll safegaurd anyway
if (!info || t.which_variant != meshtastic_Telemetry_device_metrics_tag) {
return;
@@ -692,7 +739,7 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS
*/
bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p)
{
meshtastic_NodeInfo *info = getOrCreateNode(nodeId);
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId);
if (!info) {
return false;
}
@@ -725,7 +772,7 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
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);
meshtastic_NodeInfo *info = getOrCreateNode(getFrom(&mp));
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getFrom(&mp));
if (!info) {
return;
}
@@ -742,9 +789,9 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
}
}
uint8_t NodeDB::getNodeChannel(NodeNum n)
uint8_t NodeDB::getMeshNodeChannel(NodeNum n)
{
meshtastic_NodeInfo *info = getNode(n);
meshtastic_NodeInfoLite *info = getMeshNode(n);
if (!info) {
return 0; // defaults to PRIMARY
}
@@ -753,7 +800,7 @@ uint8_t NodeDB::getNodeChannel(NodeNum n)
/// Find a node in our DB, return null for missing
/// NOTE: This function might be called from an ISR
meshtastic_NodeInfo *NodeDB::getNode(NodeNum n)
meshtastic_NodeInfo *NodeDB::getNodeInfo(NodeNum n)
{
for (int i = 0; i < *numNodes; i++)
if (nodes[i].num == n)
@@ -762,38 +809,100 @@ meshtastic_NodeInfo *NodeDB::getNode(NodeNum n)
return NULL;
}
/// Find a node in our DB, create an empty NodeInfo if missing
meshtastic_NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
/// Find a node in our DB, return null for missing
/// NOTE: This function might be called from an ISR
meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n)
{
meshtastic_NodeInfo *info = getNode(n);
for (int i = 0; i < *numMeshNodes; i++)
if (meshNodes[i].num == n)
return &meshNodes[i];
if (!info) {
if ((*numNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfo_size * 3)) {
screen->print("warning: node_db full! erasing oldest entry\n");
return NULL;
}
/// Find a node in our DB, create an empty NodeInfo if missing
meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
{
meshtastic_NodeInfoLite *lite = getMeshNode(n);
if (!lite) {
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
screen->print("warning: node_db_lite full! erasing oldest entry\n");
// look for oldest node and erase it
uint32_t oldest = UINT32_MAX;
int oldestIndex = -1;
for (int i = 0; i < *numNodes; i++) {
if (nodes[i].last_heard < oldest) {
oldest = nodes[i].last_heard;
for (int i = 0; i < *numMeshNodes; i++) {
if (meshNodes[i].last_heard < oldest) {
oldest = meshNodes[i].last_heard;
oldestIndex = i;
}
}
// Shove the remaining nodes down the chain
for (int i = oldestIndex; i < *numNodes - 1; i++) {
nodes[i] = nodes[i + 1];
for (int i = oldestIndex; i < *numMeshNodes - 1; i++) {
meshNodes[i] = meshNodes[i + 1];
}
(*numNodes)--;
(*numMeshNodes)--;
}
// add the node at the end
info = &nodes[(*numNodes)++];
lite = &meshNodes[(*numMeshNodes)++];
// everything is missing except the nodenum
memset(info, 0, sizeof(*info));
info->num = n;
memset(lite, 0, sizeof(*lite));
lite->num = n;
}
return info;
return lite;
}
void NodeDB::migrateToNodeInfoLite(const meshtastic_NodeInfo *node)
{
meshtastic_NodeInfoLite *lite = getMeshNode(node->num);
if (!lite) {
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
screen->print("warning: node_db_lite full! erasing oldest entry\n");
// look for oldest node and erase it
uint32_t oldest = UINT32_MAX;
int oldestIndex = -1;
for (int i = 0; i < *numMeshNodes; i++) {
if (meshNodes[i].last_heard < oldest) {
oldest = meshNodes[i].last_heard;
oldestIndex = i;
}
}
// Shove the remaining nodes down the chain
for (int i = oldestIndex; i < *numMeshNodes - 1; i++) {
meshNodes[i] = meshNodes[i + 1];
}
(*numMeshNodes)--;
}
// add the node at the end
lite = &meshNodes[(*numMeshNodes)++];
// everything is missing except the nodenum
memset(lite, 0, sizeof(*lite));
lite->num = node->num;
lite->snr = node->snr;
lite->last_heard = node->last_heard;
lite->channel = node->channel;
if (node->has_position) {
lite->has_position = true;
lite->position.latitude_i = node->position.latitude_i;
lite->position.longitude_i = node->position.longitude_i;
lite->position.altitude = node->position.altitude;
lite->position.location_source = node->position.location_source;
lite->position.time = node->position.time;
}
if (node->has_user) {
lite->has_user = true;
lite->user = node->user;
}
if (node->has_device_metrics) {
lite->has_device_metrics = true;
lite->device_metrics = node->device_metrics;
}
}
}
/// Record an error that should be reported via analytics
@@ -802,19 +911,19 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co
// Print error to screen and serial port
String lcd = String("Critical error ") + code + "!\n";
screen->print(lcd.c_str());
if (filename)
if (filename) {
LOG_ERROR("NOTE! Recording critical error %d at %s:%lu\n", code, filename, address);
else
} else {
LOG_ERROR("NOTE! Recording critical error %d, address=0x%lx\n", code, address);
}
// Record error to DB
myNodeInfo.error_code = code;
myNodeInfo.error_address = address;
myNodeInfo.error_count++;
error_code = code;
error_address = address;
// Currently portuino is mostly used for simulation. Make sue the user notices something really bad happend
// Currently portuino is mostly used for simulation. Make sure the user notices something really bad happened
#ifdef ARCH_PORTDUINO
LOG_ERROR("A critical failure occurred, portduino is exiting...");
exit(2);
#endif
}
}

View File

@@ -7,6 +7,7 @@
#include "MeshTypes.h"
#include "NodeStatus.h"
#include "mesh-pb-constants.h"
#include "mesh/generated/meshtastic/mesh.pb.h" // For CriticalErrorCode
/*
DeviceState versions used to be defined in the .proto file but really only this function cares. So changed to a
@@ -28,9 +29,10 @@ extern meshtastic_LocalConfig config;
extern meshtastic_LocalModuleConfig moduleConfig;
extern meshtastic_OEMStore oemStore;
extern meshtastic_User &owner;
extern meshtastic_Position localPosition;
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
uint32_t sinceLastSeen(const meshtastic_NodeInfo *n);
uint32_t sinceLastSeen(const meshtastic_NodeInfoLite *n);
/// Given a packet, return how many seconds in the past (vs now) it was received
uint32_t sinceReceived(const meshtastic_MeshPacket *p);
@@ -46,14 +48,15 @@ class NodeDB
meshtastic_NodeInfo *nodes;
pb_size_t *numNodes;
uint32_t readPointer = 0;
meshtastic_NodeInfoLite *meshNodes;
pb_size_t *numMeshNodes;
public:
bool updateGUI = false; // we think the gui should definitely be redrawn, screen will clear this once handled
meshtastic_NodeInfo *updateGUIforNode = NULL; // if currently showing this node, we think you should update the GUI
meshtastic_NodeInfoLite *updateGUIforNode = NULL; // if currently showing this node, we think you should update the GUI
Observable<const meshtastic::NodeStatus *> newStatus;
/// don't do mesh based algoritm for node id assignment (initially)
/// don't do mesh based algorithm for node id assignment (initially)
/// instead just store in flash - possibly even in the initial alpha release do this hack
NodeDB();
@@ -91,8 +94,6 @@ class NodeDB
/// @return our node number
NodeNum getNodeNum() { return myNodeInfo.my_node_num; }
size_t getNumNodes() { return *numNodes; }
/// if returns false, that means our node should send a DenyNodeNum response. If true, we think the number is okay for use
// bool handleWantNodeNum(NodeNum n);
@@ -104,29 +105,14 @@ class NodeDB
their denial?)
*/
/// Called from bluetooth when the user wants to start reading the node DB from scratch.
void resetReadPointer() { readPointer = 0; }
/// Allow the bluetooth layer to read our next nodeinfo record, or NULL if done reading
const meshtastic_NodeInfo *readNextInfo();
/// pick a provisional nodenum we hope no one is using
void pickNewNodeNum();
// get channel channel index we heard a nodeNum on, defaults to 0 if not found
uint8_t getNodeChannel(NodeNum n);
/// Find a node in our DB, return null for missing
meshtastic_NodeInfo *getNode(NodeNum n);
meshtastic_NodeInfo *getNodeByIndex(size_t x)
{
assert(x < *numNodes);
return &nodes[x];
}
uint8_t getMeshNodeChannel(NodeNum n);
/// Return the number of nodes we've heard from recently (within the last 2 hrs?)
size_t getNumOnlineNodes();
size_t getNumOnlineMeshNodes();
void initConfigIntervals(), initModuleConfigIntervals(), resetNodes();
@@ -137,15 +123,38 @@ class NodeDB
void installRoleDefaults(meshtastic_Config_DeviceConfig_Role role);
const meshtastic_NodeInfoLite *readNextMeshNode(uint32_t &readIndex);
meshtastic_NodeInfoLite *getMeshNodeByIndex(size_t x)
{
assert(x < *numMeshNodes);
return &meshNodes[x];
}
meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
size_t getNumMeshNodes() { return *numMeshNodes; }
private:
/// Find a node in our DB, create an empty NodeInfo if missing
meshtastic_NodeInfo *getOrCreateNode(NodeNum n);
/// Find a node in our DB, create an empty NodeInfoLite if missing
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
void migrateToNodeInfoLite(const meshtastic_NodeInfo *node);
/// Find a node in our DB, return null for missing
meshtastic_NodeInfo *getNodeInfo(NodeNum n);
/// Allow the bluetooth layer to read our next nodeinfo record, or NULL if done reading
const meshtastic_NodeInfo *readNextNodeInfo(uint32_t &readIndex);
size_t getNumNodes() { return *numNodes; }
meshtastic_NodeInfo *getNodeByIndex(size_t x)
{
assert(x < *numNodes);
return &nodes[x];
}
/// Notify observers of changes to the DB
void notifyObservers(bool forceUpdate = false)
{
// Notify observers of the current node state
const meshtastic::NodeStatus status = meshtastic::NodeStatus(getNumOnlineNodes(), getNumNodes(), forceUpdate);
const meshtastic::NodeStatus status = meshtastic::NodeStatus(getNumOnlineMeshNodes(), getNumMeshNodes(), forceUpdate);
newStatus.notifyObservers(&status);
}
@@ -217,11 +226,29 @@ inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t d
return defaultInterval * 1000;
}
/// Sometimes we will have Position objects that only have a time, so check for
/// valid lat/lon
static inline bool hasValidPosition(const meshtastic_NodeInfo *n)
{
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
}
static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n)
{
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
}
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
* might have changed is incremented. Allows others to detect they might now be on a new channel.
*/
extern uint32_t radioGeneration;
extern meshtastic_CriticalErrorCode error_code;
/*
* A numeric error address (nonzero if available)
*/
extern uint32_t error_address;
#define Module_Config_size \
(ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \
ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \

View File

@@ -5,6 +5,7 @@
#include "NodeDB.h"
#include "PowerFSM.h"
#include "RadioInterface.h"
#include "TypeConversions.h"
#include "configuration.h"
#include "main.h"
#include "xmodem.h"
@@ -17,6 +18,8 @@
#error ToRadio is too big
#endif
#include "mqtt/MQTT.h"
PhoneAPI::PhoneAPI()
{
lastContactMsec = millis();
@@ -40,9 +43,8 @@ void PhoneAPI::handleStartConfig()
state = STATE_SEND_MY_INFO;
LOG_INFO("Starting API client config\n");
nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
// this will break once we have multiple instances of PhoneAPI running independently
nodeInfoForPhone.num = 0; // Don't keep returning old nodeinfos
resetReadIndex();
}
void PhoneAPI::close()
@@ -54,6 +56,7 @@ void PhoneAPI::close()
unobserve(&xModem.packetReady);
releasePhonePacket(); // Don't leak phone packets on shutdown
releaseQueueStatusPhonePacket();
releaseMqttClientProxyPhonePacket();
onConnectionChanged(false);
}
@@ -98,6 +101,12 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
LOG_INFO("Got xmodem packet\n");
xModem.handlePacket(toRadioScratch.xmodemPacket);
break;
case meshtastic_ToRadio_mqttClientProxyMessage_tag:
LOG_INFO("Got MqttClientProxy message\n");
if (mqtt && moduleConfig.mqtt.proxy_to_client_enabled) {
mqtt->onClientProxyReceive(toRadioScratch.mqttClientProxyMessage);
}
break;
default:
// Ignore nop messages
// LOG_DEBUG("Error: unexpected ToRadio variant\n");
@@ -144,25 +153,23 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
LOG_INFO("getFromRadio=STATE_SEND_MY_INFO\n");
// If the user has specified they don't want our node to share its location, make sure to tell the phone
// app not to send locations on our behalf.
myNodeInfo.has_gps = gps && gps->isConnected(); // Update with latest GPS connect info
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag;
fromRadioScratch.my_info = myNodeInfo;
state = STATE_SEND_NODEINFO;
service.refreshMyNodeInfo(); // 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;
case STATE_SEND_NODEINFO: {
LOG_INFO("getFromRadio=STATE_SEND_NODEINFO\n");
const meshtastic_NodeInfo *info = nodeInfoForPhone;
nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time
if (info) {
LOG_INFO("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->last_heard, info->user.id,
info->user.long_name);
if (nodeInfoForPhone.num != 0) {
LOG_INFO("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", nodeInfoForPhone.num, nodeInfoForPhone.last_heard,
nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name);
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag;
fromRadioScratch.node_info = *info;
fromRadioScratch.node_info = nodeInfoForPhone;
// Stay in current state until done sending nodeinfos
nodeInfoForPhone.num = 0; // We just consumed a nodeinfo, will need a new one next time
} else {
LOG_INFO("Done sending nodeinfos\n");
state = STATE_SEND_CHANNELS;
@@ -297,12 +304,16 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
break;
case STATE_SEND_PACKETS:
// Do we have a message from the mesh?
// Do we have a message from the mesh or packet from the local device?
LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n");
if (queueStatusPacketForPhone) {
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_queueStatus_tag;
fromRadioScratch.queueStatus = *queueStatusPacketForPhone;
releaseQueueStatusPhonePacket();
} else if (mqttClientProxyMessageForPhone) {
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_mqttClientProxyMessage_tag;
fromRadioScratch.mqttClientProxyMessage = *mqttClientProxyMessageForPhone;
releaseMqttClientProxyPhonePacket();
} else if (xmodemPacketForPhone.control != meshtastic_XModem_Control_NUL) {
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_xmodemPacket_tag;
fromRadioScratch.xmodemPacket = xmodemPacketForPhone;
@@ -355,6 +366,14 @@ void PhoneAPI::releaseQueueStatusPhonePacket()
}
}
void PhoneAPI::releaseMqttClientProxyPhonePacket()
{
if (mqttClientProxyMessageForPhone) {
service.releaseMqttClientProxyMessageToPool(mqttClientProxyMessageForPhone);
mqttClientProxyMessageForPhone = NULL;
}
}
/**
* Return true if we have data available to send to the phone
*/
@@ -372,14 +391,20 @@ bool PhoneAPI::available()
return true;
case STATE_SEND_NODEINFO:
if (!nodeInfoForPhone)
nodeInfoForPhone = nodeDB.readNextInfo();
if (nodeInfoForPhone.num == 0) {
auto nextNode = nodeDB.readNextMeshNode(readIndex);
if (nextNode) {
nodeInfoForPhone = ConvertToNodeInfo(nextNode);
}
}
return true; // Always say we have something, because we might need to advance our state machine
case STATE_SEND_PACKETS: {
if (!queueStatusPacketForPhone)
queueStatusPacketForPhone = service.getQueueStatusForPhone();
bool hasPacket = !!queueStatusPacketForPhone;
if (!mqttClientProxyMessageForPhone)
mqttClientProxyMessageForPhone = service.getMqttClientProxyMessageForPhone();
bool hasPacket = !!queueStatusPacketForPhone || !!mqttClientProxyMessageForPhone;
if (hasPacket)
return true;
@@ -423,8 +448,9 @@ int PhoneAPI::onNotify(uint32_t newValue)
if (state == STATE_SEND_PACKETS) {
LOG_INFO("Telling client we have new packets %u\n", newValue);
onNowHasData(newValue);
} else
} else {
LOG_DEBUG("(Client not yet interested in packets)\n");
}
return 0;
}
}

View File

@@ -50,14 +50,20 @@ class PhoneAPI
// Keep QueueStatus packet just as packetForPhone
meshtastic_QueueStatus *queueStatusPacketForPhone = NULL;
// Keep MqttClientProxyMessage packet just as packetForPhone
meshtastic_MqttClientProxyMessage *mqttClientProxyMessageForPhone = NULL;
/// We temporarily keep the nodeInfo here between the call to available and getFromRadio
const meshtastic_NodeInfo *nodeInfoForPhone = NULL;
meshtastic_NodeInfo nodeInfoForPhone = meshtastic_NodeInfo_init_default;
meshtastic_ToRadio toRadioScratch = {
0}; // this is a static scratch object, any data must be copied elsewhere before returning
/// Use to ensure that clients don't get confused about old messages from the radio
uint32_t config_nonce = 0;
uint32_t readIndex = 0;
void resetReadIndex() { readIndex = 0; }
public:
PhoneAPI();
@@ -123,6 +129,8 @@ class PhoneAPI
void releaseQueueStatusPhonePacket();
void releaseMqttClientProxyPhonePacket();
/// begin a new connection
void handleStartConfig();

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