Compare commits

..

361 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
Ben Meadors
7ef12c77a8 Add initial screen for receiving waypoints (#2452) 2023-05-01 16:10:27 -05:00
Mark Trevor Birss
a27d354364 Add board - BPI PicoW ESP32-S3 SX1262 (#2450)
* Add files via upload

* Add files via upload
2023-05-01 07:12:00 -05:00
Manuel Verch
6e26f95df9 Make trunk happy again 2023-04-22 09:08:55 +02:00
Manuel Verch
5dfb5172c2 try-fix: router goes sporadically into DS 2023-04-22 09:08:55 +02:00
Thomas Göttgens
e0bb95ca94 implement dynamic userbutton overwrite. fix #2434 2023-04-21 16:50:22 +02:00
Thomas Göttgens
1621fbb5ab add debug/info print 2023-04-21 16:03:48 +02:00
Thomas Göttgens
ac40f77694 Draft for now, please test 2023-04-21 16:03:48 +02:00
Thomas Göttgens
9700fa55a3 Merge pull request #2438 from meshtastic/mqtt-debug-fix
fix topic construction for mqtt debug
2023-04-18 14:30:59 +02:00
Thomas Göttgens
87c59d7d61 fmt 2023-04-18 14:08:06 +02:00
Thomas Göttgens
584615bb4b fix topic construction for mqtt debug 2023-04-18 13:37:50 +02:00
github-actions[bot]
c452c2ab40 [create-pull-request] automated change (#2437)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-04-17 19:42:54 -05:00
github-actions[bot]
d43ddc9ec2 [create-pull-request] automated change (#2436) 2023-04-17 15:42:42 -05:00
Thomas Göttgens
a76cb94851 Revert "Trying to debug transient "disconnects" in iOS (#2312)" (#2435)
This reverts commit d17aafa91a.
2023-04-17 11:22:12 -05:00
Thomas Göttgens
da75ae21ff Merge pull request #2298 from meshtastic/2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low
2264 Check for memory before extending the nodedb
2023-04-15 09:13:55 +02:00
Thomas Göttgens
a30c07e6b4 Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-04-14 19:56:01 +02:00
Thomas Göttgens
309d4fc7f2 add flush to filesystem before closing write file. 2023-04-14 13:25:06 +02:00
Thomas Göttgens
a13775bd70 Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-04-13 23:50:21 +02:00
Thomas Göttgens
b43a5bc4f8 Fix missing msh default topic. 2023-04-13 23:17:05 +02:00
Thomas Göttgens
ec44ca49fd Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-04-13 23:09:33 +02:00
Thomas Göttgens
5d41e9fe9d don't grow nodedb if memory is tight.
also remove unconditional reboot on low heap. This is counter productive with this change
2023-04-13 23:09:02 +02:00
Thomas Göttgens
7bd836673e return shutdown time to 5 seconds. 2023-04-13 19:53:56 +02:00
Thomas Göttgens
e0da661632 remove screen brightness again 2023-04-13 15:32:29 +02:00
Thomas Göttgens
a9ce4338ff update library version 2023-04-12 19:04:19 +02:00
Thomas Göttgens
a284439d7e Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-04-12 16:27:36 +02:00
Thomas Göttgens
10fac072bb move codec2 repo to org 2023-04-12 14:39:25 +02:00
Thomas Göttgens
d60ccb42da pretty print 2023-04-12 10:06:04 +02:00
thebentern
3598351689 [create-pull-request] automated change 2023-04-11 20:14:31 +02:00
Thomas Göttgens
74ed166ff0 Merge branch 'master' of github.com:meshtastic/firmware 2023-04-11 20:11:04 +02:00
Thomas Göttgens
0afeba0c86 generate dynamic device array for use in CI scripts
Usage: generate_ci_matrix.py platform [extra]
e.g. generate_ci_matrix.py esp32 or generate_ci_matrix.py esp32 extra
2023-04-11 20:10:54 +02:00
github-actions[bot]
ee971e376a [create-pull-request] automated change (#2424)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-04-11 08:01:49 -05:00
Thomas Göttgens
eeeb7c5080 i wasn't asking... 2023-04-11 14:37:08 +02:00
Thomas Göttgens
f526c4cc5a trxfix portduino 2023-04-11 14:37:08 +02:00
Thomas Göttgens
a9eb19fc62 fix parameters and compilation 2023-04-11 14:37:08 +02:00
Thomas Göttgens
29c13b5c30 resolve #2364
- fix wrong debug print
- change shutdown logic for t-beam if PMU is detected
- wait for 10 seconds instead of 5 for shutdown and resurrect screen brightness adjust for @karamo
2023-04-11 14:37:08 +02:00
Manuel Verch
f0c4c18a79 Fix for nodeInfo change to inform phone 2023-04-11 14:01:01 +02:00
Thomas Göttgens
320bf57687 tryfix #2416 - lock some guards. 2023-04-10 17:00:15 +02:00
Ben Meadors
4b89f7dfcb Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-04-07 07:55:26 -05:00
Thomas Göttgens
43cff7adc9 Implement #2380 (#2418) 2023-04-07 07:52:23 -05:00
github-actions[bot]
d4e42898b1 [create-pull-request] automated change (#2417)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-04-07 07:14:40 -05:00
Manuel Verch
82ab38d3e6 Revert changes on wakeup 2023-04-04 23:19:36 +02:00
github-actions[bot]
aa96ea02c6 [create-pull-request] automated change (#2411)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-04-04 14:13:26 -05:00
Ben Meadors
242f880764 Dear trunk, please don't be petty 2023-04-04 09:42:12 -05:00
Ben Meadors
de08360271 Protos tag for release 2023-04-04 08:15:59 -05:00
ghostop14
990d418dc8 Add MQTT TLS Support for WIFI-Enabled Devices (#2410)
* Testing TLS MQTT Support

* Working TLS connections

* Testing TLS MQTT Support

* Working TLS connections

* Added protobuf support for mqtt.tls_enabled

* fix 'em up good

* don't commit this stuff, jeeez

* there i fixed it

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2023-04-04 08:14:47 -05:00
Ben Meadors
f8db02c622 Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-04-04 07:22:40 -05:00
Thomas Göttgens
fc8d16bb08 Merge pull request #2403 from mverch67/fix-2402
Fix for device display issues
2023-04-03 23:55:33 +02:00
Thomas Göttgens
af65013e49 Merge branch 'master' into fix-2402 2023-04-03 23:06:48 +02:00
Manuel
b1937e03ac fix: store NodeDB persistently (#2405)
* fix for 2404

* fix for 2404

* removed superfluous saveToDisk in reloadOwner()
2023-04-03 16:01:05 -05:00
Manuel Verch
23e6bc32c0 make cpptools happy 2023-04-03 20:14:57 +02:00
Manuel Verch
bd1e747fc9 Merge branch 'fix-2402' of https://github.com/mverch67/meshtastic-firmware into fix-2402 2023-04-03 19:46:52 +02:00
Manuel Verch
3c0817340a Fixed blank screen button issue and SX126x wakeup 2023-04-03 19:45:12 +02:00
Manuel Verch
9a42861766 make trunk happy 2023-04-03 18:06:36 +02:00
Manuel Verch
038ff0f6cb Fix for device display issues 2023-04-03 18:06:36 +02:00
github-actions[bot]
918b509be8 [create-pull-request] automated change (#2408)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-04-03 10:45:37 -05:00
Manuel Verch
9239698004 make trunk happy 2023-04-03 08:52:21 +02:00
Manuel Verch
71479a6b17 Fix for device display issues 2023-04-02 21:28:12 +02:00
Ben Meadors
b4bcae98cd Fixed invalid channel name text (#2400) 2023-04-02 08:33:38 -05:00
Thomas Göttgens
294771cb44 fix -705 error on SX128x and some SX126x 2023-04-02 15:04:50 +02:00
Thomas Göttgens
1398611276 trunk fmt 2023-04-02 11:35:25 +02:00
Vladislav Osmanov
fbc3b2beee missing EXT_PWR_DETECT pinMode definition 2023-04-02 11:35:25 +02:00
Vladislav Osmanov
6bf538e26f EXT_PWR_DETECT pin to detect external power source for boards without the power management chip 2023-04-02 11:35:25 +02:00
Thomas Göttgens
713b5fbe96 try to update trunk to latest version. 2023-03-31 12:51:26 +02:00
Thomas Göttgens
ed96321406 fix newline detection in error printing
Our code check for newline in the format string, not in the parameter
2023-03-31 11:04:15 +02:00
Thomas Göttgens
39d8ae64e7 Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-30 11:10:18 +02:00
Thomas Göttgens
3f07251d23 fmt 2023-03-30 10:46:39 +02:00
Mark Trevor Birss
657f22d058 Update EInkDisplay2.cpp 2023-03-30 10:46:39 +02:00
github-actions[bot]
bf1fbc6c0d [create-pull-request] automated change (#2395)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-03-29 19:19:19 -05:00
Ben Meadors
5679a82195 Support double tap as button press for supported accelerometers (#2393)
* For Garth

* Push it real good

* Wut

* Double tap

* Move disable logic

* Actually return

* Reinitialize setClick in thread body

* Initialize later so that we actually have nodedb on init

* Fixes
2023-03-29 13:04:02 -05:00
Thomas Göttgens
2edc35d34b Logic Late-Fix to the last PR 2023-03-29 15:14:48 +02:00
sbias
26d18244f0 Add nodedb channel handling (#2384)
* send ourNodeInfo to channel we got a message we heared someone new

* store node-channel into nodeDB

* use channel from nodeDb to send local messages

* update protobufs

* fmt and fix braces

* respect requested channel for local send, only store channel while getting a nodeinfo packet

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-03-29 06:51:22 -05:00
Thomas Göttgens
82ba59765c trunk it baby 2023-03-29 13:41:45 +02:00
Mark Trevor Birss
7930aa1635 Update platformio.ini 2023-03-29 13:41:45 +02:00
Mark Trevor Birss
c55751964e Update platformio.ini 2023-03-29 13:41:45 +02:00
Mark Trevor Birss
b9b1cce6a5 Update platformio.ini 2023-03-29 13:41:45 +02:00
Mark Trevor Birss
044ef75fef Update platformio.ini 2023-03-29 13:41:45 +02:00
Mark Trevor Birss
9f940139a0 Update platformio.ini 2023-03-29 13:41:45 +02:00
Mark Trevor Birss
fdb09d4fba Add files via upload 2023-03-29 13:41:45 +02:00
Mark Trevor Birss
1968f3c45b Delete EInkDisplay2.cpp 2023-03-29 13:41:45 +02:00
Mark Trevor Birss
790df42987 Add files via upload 2023-03-29 13:41:45 +02:00
Mark Trevor Birss
9a9279dd78 Add files via upload 2023-03-29 13:41:45 +02:00
thebentern
1e54a5d45c [create-pull-request] automated change 2023-03-28 12:57:23 +02:00
Ben Meadors
23272daffe Threshold based smart position broadcasts (#2388)
* Overhaul smart broadcast with new thresholds

* Fixed badly spelt protos

* That's not the right thing

* Format specifiers

* Fmt

* Units

* Default distance threshold of 100
2023-03-27 14:09:22 -05:00
Thomas Göttgens
6e685b0a54 Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-27 15:31:32 +02:00
Dan Fay
1af7e48136 Fixed the semi-silent failure to regenerate protobufs on Linux (#2383)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-03-27 06:52:48 -05:00
lewishe
eda00b7b9c Change to Variation Macro Definition 2023-03-27 11:27:57 +02:00
Thomas Göttgens
1898fe850e trunk format 2023-03-27 11:27:57 +02:00
lewishe
15dbe5da97 Added t-beam v1.2 support 2023-03-27 11:27:57 +02:00
GUVWAF
8f736c8ecc Remove sending network ping to displayed node on interval 2023-03-26 16:16:01 +02:00
Thomas Göttgens
8a81f190b8 Merge pull request #2386 from meshtastic/channel-num-fix
fix channel num in json output
2023-03-25 20:35:20 +01:00
Thomas Göttgens
1425657a3c fix channel num in json output 2023-03-25 20:14:04 +01:00
Thomas Göttgens
02041cb605 Merge pull request #2385 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2023-03-25 14:56:33 +01:00
caveman99
1f130d671b [create-pull-request] automated change 2023-03-25 13:38:35 +00:00
Thomas Göttgens
d62e56f428 Merge pull request #2381 from meshtastic/HPD17-PA
Add Power Restraint for 1280 PA Model
2023-03-25 14:24:02 +01:00
Thomas Göttgens
5ac24bb33b Update SX128xInterface.cpp 2023-03-25 14:23:30 +01:00
Thomas Göttgens
2c259b8464 Add Power Restraint for 1280 PA Model
Add Debug Print for all module parameters
Add RX/TX Switch to 1280
2023-03-24 16:57:30 +01:00
github-actions[bot]
9d6e1ce8e5 [create-pull-request] automated change (#2375)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-03-23 13:13:47 -05:00
code8buster
958d2cf630 Remove call to randomSeed() (#2374)
This function causes the new arduino-esp32 core to revert to the pseudorandom behavior specified in Arduino.
Calls to random() automatically use esp_random() if randomSeed or useRealRandomGenerator(false) aren't called.
Tentative fix for #2357
2023-03-23 12:05:12 -05:00
Ben Meadors
5cb1f96240 Use accelerometer to wake up screen (#2371)
* WIP accelerometer tinkering

* Debug logging

* RAK LIS3DH sensor

* Deconflict temperature sensor and LIS3DH

* Finishing up

* StateON

* Protobufs

* Default of none

* Formatting
2023-03-23 11:32:04 -05:00
Thomas Göttgens
78522e750c Merge pull request #2304 from meshtastic/ESP32C3-RISC
ESP32C3 RISC SOC
2023-03-21 17:21:31 +01:00
Thomas Göttgens
75db8c2d2e the target starts up and works for a few seconds before crashing. Good enough for others to continue the work :-) 2023-03-21 16:24:24 +01:00
Thomas Göttgens
91be22b341 Merge branch 'master' into ESP32C3-RISC 2023-03-21 09:31:30 +01:00
Thomas Göttgens
cc64c3d61a Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-21 09:30:54 +01:00
github-actions[bot]
36b00dba86 [create-pull-request] automated change (#2367)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-03-18 08:47:40 -05:00
Ben Meadors
3bb8cd7613 Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-18 07:26:44 -05:00
GUVWAF
8c68d888c8 SX126x: Try next Interface when chip not found (#2363)
* If chip was not found, return false for init()

* SX1268: Only overwrite frequency when out of bounds
Happens when region is still UNSET
2023-03-18 07:23:37 -05:00
Manuel
1f99d4756a Fix: Sporadig crashes and reboot (#2366)
* Fix: Sporadig crashes with reboot

* Revert "Fix: Sporadig crashes with reboot"

This reverts commit 59b65749f5.

* Fix: Sporadig crashes and reboot
2023-03-17 19:53:29 -05:00
Andre K
7bbfa48b5d fix channel_num log (#2361)
* fix channel_num variable

* fix channel_num log instead
2023-03-17 13:36:10 -05:00
Manuel
b398f31b64 Fix heap leak mentioned in #2358 (#2359)
* Fix heap leak mentioned in #2358

* Additional fix for #2359
2023-03-14 16:50:32 -05:00
rcarteraz
e03a2f8f7f Add V3 and TBeam S3 to hardware 2023-03-13 19:15:38 -03:00
github-actions[bot]
d92a003d8e [create-pull-request] automated change (#2354)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-03-13 14:07:28 -05:00
Thomas Göttgens
8db7316ae1 Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-12 20:22:46 +01:00
Thomas Göttgens
3c2e615650 Merge branch 'master' into ESP32C3-RISC 2023-03-12 20:22:38 +01:00
Thomas Göttgens
6d202158ba add (and fix) CPU Shutdown Flags 2023-03-12 20:20:55 +01:00
Thomas Göttgens
c288974b67 don't adjust brightness on long press any more 2023-03-12 20:20:55 +01:00
Thomas Göttgens
9b1d461567 add NO_SCREEN shim 2023-03-12 20:20:55 +01:00
Thomas Göttgens
210e3e09d5 enable deep sleep behaviour for ESP32 2023-03-12 20:20:55 +01:00
Thomas Göttgens
0d001423c8 woops 2023-03-12 20:20:55 +01:00
Thomas Göttgens
a83d5ada86 - implement shutdown (deep sleep forever) on ESP32
- Clean up shutdown and delayed shutdown code conditionals.
- clean up inputbroker includes
2023-03-12 20:20:55 +01:00
Thomas Göttgens
4573db4665 Merge branch 'master' into ESP32C3-RISC 2023-03-12 20:19:43 +01:00
Thomas Göttgens
d2c72fae00 Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-12 19:29:42 +01:00
andrekir
c9686d2f62 remove PIN_EINK_EN from RAK4631 variants 2023-03-12 19:29:12 +01:00
Andre K
634251834f fix rak4631_epaper PIN_EINK_EN
revert 088ab106dd
2023-03-12 19:29:12 +01:00
GUVWAF
6d443d2c67 SX126x/8x: Also use PREAMBLE_DETECTED IRQ flag for actively receiving check (#2349)
* Use startReceive() instead of startReceiveDutyCycleAuto()

* Add preamble detected IRQ

* Escape from 'freeze' state when packet should have been received

* Use RADIOLIB_GODMODE for access to clearIrqStatus

* SX126x: Better handling of false preamble detections

* SX128x: Add preamble IRQ and false detection handling to active receiving check

* Remove unnecessary function declaration

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-03-11 12:59:29 -06:00
thebentern
9cadc0a16f [create-pull-request] automated change 2023-03-11 12:08:25 +01:00
Ben Meadors
2e3b86608a Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-10 19:50:41 -06:00
Ben Meadors
dc2ca9c32b Report special battery_level of > 100 instead of zero to indicate USB (#2341)
* Report special battery_level of > 100 instead of zero to indicate USB

* Protos

* Helps if you click save

* Wrong method

* Fmt
2023-03-10 19:50:08 -06:00
Thomas Göttgens
e0a6a37bef Merge branch '2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low' of github.com:meshtastic/firmware into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-10 21:39:33 +01:00
Thomas Göttgens
57fc9baafc cmsis is donning his own HardFault Handler 2023-03-10 21:39:21 +01:00
Thomas Göttgens
033e988e6f Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-10 19:38:14 +01:00
Ben Meadors
fddc49273e Reboot seconds bump 2023-03-09 16:08:18 -06:00
Ben Meadors
e737a22120 Platform updates (#2340)
* 6.1.0

* Update libs

* Update nrf52 while we're at it

* Remove temporary heltec platform packages

* Update install scripts to flash s3 ota partition bin
2023-03-09 12:45:38 -06:00
Thomas Göttgens
a8f2e3ddbd pack the bleota-s3 in the omnibus zip 2023-03-09 09:10:16 +01:00
Thomas Göttgens
67be6aa53b fmt 2023-03-09 09:04:08 +01:00
Thomas Göttgens
68e17ab905 avoid a couple of downloads and build seconds by building the littlefs for the current target instead of 'tbeam' 2023-03-09 09:00:59 +01:00
Thomas Göttgens
a56403987b use the s3 build script 2023-03-09 08:45:49 +01:00
Thomas Göttgens
7acacb3bba Add a separate workflow for s3 boards
they use the same batch file but require a different OTA firmware.
2023-03-09 08:45:49 +01:00
A. Rager
e6d69e2b67 Refactor i2cScan.h To Handle 2 Bus (#2337)
* Break i2cScan out into a set of classes for scanning i2c

* refactor i2cscan addresses to be structs that allow addressing by port + address

* build whoopsies

* trunk fmt

* trunk fmt

* lost some build fixes from the merge

* more cleaning for build safety, RTC behavior
2023-03-08 21:13:46 -06:00
Thomas Göttgens
9150c2e568 fix stuff i somehow inadvertently broke. 2023-03-08 17:12:25 +01:00
Thomas Göttgens
944d5066e9 update lib dependency 2023-03-08 17:12:25 +01:00
Thomas Göttgens
a538a96c90 fmt 2023-03-08 17:12:25 +01:00
Thomas Göttgens
31ef82557f try revert protos 2023-03-08 17:12:25 +01:00
Thomas Göttgens
9d440b7dba revert overcommit 2023-03-08 17:12:25 +01:00
Thomas Göttgens
267db05d69 - G1 Explorer use correct display controller
- adhere UA font in modules
2023-03-08 17:12:25 +01:00
github-actions[bot]
20bcf310d1 [create-pull-request] automated change (#2334)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-03-06 17:09:41 -06:00
Thomas Göttgens
a95b6aff01 Merge branch 'master' into ESP32C3-RISC 2023-03-05 14:55:30 +01:00
Thomas Göttgens
b249970a12 add rudimentary exception decoder for RISC-V CPU 2023-03-05 14:55:12 +01:00
Thomas Göttgens
fe926eedba Merge branch 'ESP32C3-RISC' of github.com:meshtastic/firmware into ESP32C3-RISC 2023-03-04 23:17:56 +01:00
Thomas Göttgens
4355f51a90 fmt 2023-03-04 17:25:55 +01:00
Thomas Göttgens
ecd67f0a85 disable the frequency switcher for the C3 CPU... 2023-03-04 17:25:55 +01:00
Thomas Göttgens
0940c6462b Leaving this here in case someone ever needs int :-) 2023-03-04 17:25:55 +01:00
Thomas Göttgens
a47364f07b Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-03-04 17:24:16 +01:00
Thomas Göttgens
a3f1e53017 fmt 2023-02-24 09:53:25 +01:00
Thomas Göttgens
0243922d64 Merge branch 'ESP32C3-RISC' of github.com:meshtastic/firmware into ESP32C3-RISC 2023-02-24 09:32:43 +01:00
Thomas Göttgens
baeb2807a4 disable the frequency switcher for the C3 CPU... 2023-02-24 09:32:31 +01:00
Thomas Göttgens
9a8bfa113d Leaving this here in case someone ever needs int :-) 2023-02-23 22:55:50 +01:00
Thomas Göttgens
82b14fe07c Leaving this here in case someone ever needs int :-) 2023-02-23 22:54:07 +01:00
Ben Meadors
48a407bf5c Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-02-23 07:10:41 -06:00
Thomas Göttgens
2475debb2a Merge branch 'master' into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low 2023-02-22 10:15:09 +01:00
Thomas Göttgens
568899031d Check if there's something there before we free it 2023-02-22 10:07:03 +01:00
Thomas Göttgens
f1c457f0c3 tryfix #2228 as suggested by @mverch67 2023-02-22 10:07:03 +01:00
Ben Meadors
c8399b7256 Remove extra 2023-02-22 10:07:03 +01:00
github-actions[bot]
63005a94fd [create-pull-request] automated change (#2294)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-02-22 10:07:03 +01:00
Ben Meadors
9b4a59f92d Add da explora 2023-02-22 10:07:03 +01:00
GUVWAF
2472d0947f RadioLib's startChannel returns LORA_DETECTED for SX126x and SX128x (#2293) 2023-02-22 10:07:03 +01:00
Ben Meadors
a92b2ec6ca Trunk fix 2023-02-22 10:07:03 +01:00
Ben Meadors
548bec026a Trunk fmt 2023-02-22 10:07:03 +01:00
Krezalis
ce882b389a Update Screen.h (#2285)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-02-22 10:07:03 +01:00
Krezalis
25fd9d2d1d Add Ukrainian symbols (#2286)
* Update Screen.cpp

* Add files via upload

* Update Screen.cpp

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-02-22 10:07:03 +01:00
GUVWAF
83a201fe86 Use LORA_DIO1 as RadioLib GPIO for SX127x chips (#2290)
* When channel is active, first try receiving that packet
Afterwards we'll try transmitting again

* Remove setStandby in startSend
Already done in isChannelActive()

* Set LORA_DIO1 as RadioLib GPIO for SX127x

* LORA_DIO1 for Heltec v1, overlaps with GPS_TX
Set to RADIOLIB_NC for now

* If receive was not successful, startReceive doesn't trigger the interrupt
So we have to go back to transmitting anyway

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-02-22 10:07:03 +01:00
Ben Meadors
462ee3d921 Missed a reference 2023-02-22 10:07:03 +01:00
Ben Meadors
0104246067 Remove pico from build for now 2023-02-22 10:07:03 +01:00
Ben Meadors
3f5c0cb6ac Don't auto set to default primary channel 2023-02-22 10:07:03 +01:00
Neil Hao
fa371bc844 Update extensions.json 2023-02-22 10:07:03 +01:00
neil
090f42f51f 'nano-g1-explorer' 2023-02-22 10:07:03 +01:00
thebentern
c2ff6f2f7c [create-pull-request] automated change 2023-02-22 10:07:03 +01:00
Thomas Göttgens
181832aedd Merge pull request #2282 from meshtastic/master
Catch up
2023-02-17 12:32:33 +01:00
Thomas Göttgens
4967a16abe - Abstract the memory stats into its own class.
- Fix a bug with debug mqtt
- nrf52 needs more love, there's a strange error while linking. Help appreciated
2023-02-17 12:31:51 +01:00
Thomas Göttgens
e2f5e9206d label boards as secondary to split the core firmware archive by support level.
Ref: https://docs.platformio.org/en/latest/scripting/examples/platformio_ini_custom_options.html
2023-02-10 01:40:47 +01:00
Thomas Göttgens
57b8e3732e Update to Espressif32 Platform 6.0 and ESP-IDF 5.0 2023-02-10 01:40:47 +01:00
Ben Meadors
f0d27f896a Add changed back 2023-02-10 01:40:47 +01:00
Ben Meadors
e74b180655 Remove setOwner's business logic for licensed operation 2023-02-10 01:40:47 +01:00
Ben Meadors
88a44eede0 Rebroadcast mode to local_only for hams 2023-02-10 01:40:47 +01:00
331 changed files with 10826 additions and 2065 deletions

View File

@@ -32,16 +32,24 @@ body:
options:
- Not Applicable
- T-Beam
- T-Beam S3
- T-Beam 0.7
- 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

59
.github/workflows/build_esp32_s3.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
name: Build ESP32-S3
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-esp32-s3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
with:
repo: meshtastic/firmware-ota
file: firmware-s3.bin
target: release/bleota-s3.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.bin
release/*.elf

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:
@@ -42,7 +48,8 @@ jobs:
uses: ./.github/actions/setup-base
- name: Trunk Check
uses: trunk-io/trunk-action@v1
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
- name: Check ${{ matrix.board }}
run: bin/check-all.sh ${{ matrix.board }}
@@ -56,28 +63,42 @@ 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: heltec-v3
- board: heltec-wsl-v3
- 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
- board: m5stack-core
- board: m5stack-coreink
- board: tbeam-s3-core
- board: tlora-t3s3-v1
- board: nano-g1-explorer
uses: ./.github/workflows/build_esp32.yml
with:
board: ${{ matrix.board }}
build-esp32-s3:
strategy:
fail-fast: false
matrix:
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 }}
build-nrf52:
strategy:
fail-fast: false
@@ -86,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
@@ -138,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
@@ -156,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: .
@@ -176,7 +202,8 @@ jobs:
gather-artifacts:
runs-on: ubuntu-latest
needs: [build-esp32, 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
@@ -193,7 +220,7 @@ jobs:
id: version
- name: Move files up
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v3
@@ -232,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 }}
@@ -291,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

3
.trunk/configs/.flake8 Normal file
View File

@@ -0,0 +1,3 @@
# Autoformatter friendly flake8 config (all formatting rules disabled)
[flake8]
extend-ignore = D1, D2, E1, E2, E3, E501, W1, W2, W3, W5

View File

@@ -0,0 +1,2 @@
[settings]
profile=black

View File

@@ -0,0 +1,10 @@
rules:
quoted-strings:
required: only-when-needed
extra-allowed: ["{|}"]
empty-values:
forbid-in-block-mappings: true
forbid-in-flow-mappings: true
key-duplicates: {}
octal-values:
forbid-implicit-octal: true

5
.trunk/configs/ruff.toml Normal file
View File

@@ -0,0 +1,5 @@
# Generic, formatter-friendly config.
select = ["B", "D3", "D4", "E", "F"]
# Never enforce `E501` (line length violations). This should be handled by formatters.
ignore = ["E501"]

View File

@@ -1,28 +1,43 @@
version: 0.1
cli:
version: 1.3.1
version: 1.9.1
plugins:
sources:
- id: trunk
ref: v0.0.8
ref: v0.0.17
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- taplo@0.7.0
- ruff@0.0.265
- yamllint@1.31.0
- isort@5.12.0
- markdownlint@0.34.0
- oxipng@8.0.0
- svgo@3.0.2
- 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.15.2
- gitleaks@8.16.3
- clang-format@14.0.0
- prettier@2.8.3
- 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:
enabled:
- go@1.18.3
- python@3.10.8
- go@1.19.5
- node@18.12.1
actions:
disabled:

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.0.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,8 +38,9 @@ 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
caveman99/ESP32 Codec2@^1.0.1
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
lib_ignore =
segger_rtt
@@ -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

5
arch/esp32/esp32c3.ini Normal file
View File

@@ -0,0 +1,5 @@
[esp32c3_base]
extends = esp32_base
monitor_speed = 115200
monitor_filters = esp32_c3_exception_decoder

View File

@@ -1,47 +1,16 @@
[esp32s2_base]
extends = arduino_base
platform = platformio/espressif32@^6.0.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
caveman99/ESP32 Codec2@^1.0.1
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.0.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
caveman99/ESP32 Codec2@^1.0.1
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.4.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

@@ -34,7 +34,7 @@ SRCBIN=.pio/build/$1/firmware.bin
cp $SRCBIN $OUTDIR/$basename-update.bin
echo "Building Filesystem for ESP32 targets"
pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
pio run --environment $1 -t buildfs
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

View File

@@ -30,7 +30,13 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
%PYTHON% -m esptool --baud 115200 erase_flash
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
@REM Account for S3 board's different OTA partition
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% IF x%FILENAME:t-deck=%==x%FILENAME% IF x%FILENAME:wireless-paper=%==x%FILENAME% IF x%FILENAME:wireless-tracker=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
)
for %%f in (littlefs-*.bin) do (
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
)

View File

@@ -49,7 +49,12 @@ if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
# Account for S3 board's different OTA partition
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
fi
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
else

38
bin/generate_ci_matrix.py Executable file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/env python
"""Generate the CI matrix"""
import configparser
import json
import os
import sys
rootdir = "variants/"
options = sys.argv[1:]
outlist = []
if len(options) < 1:
print(json.dumps(outlist))
exit()
for subdir, dirs, files in os.walk(rootdir):
for file in files:
if file == "platformio.ini":
config = configparser.ConfigParser()
config.read(subdir + "/" + file)
for c in config.sections():
if c.startswith("env:"):
section = config[c].name[4:]
if "extends" in config[config[c].name]:
if config[config[c].name]["extends"] == options[0] + "_base":
if "board_level" in config[config[c].name]:
if (
config[config[c].name]["board_level"] == "extra"
) & ("extra" in options):
outlist.append(section)
else:
outlist.append(section)
print(json.dumps(outlist))

View File

@@ -1,5 +1 @@
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs ..\protobufs\meshtastic\*.proto
@REM cd ../src/mesh/generated/meshtastic
@REM sed -i 's/#include "meshtastic/#include "./g' *
@REM sed -i 's/meshtastic_//g' *
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --experimental_allow_proto3_optional --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs ..\protobufs\meshtastic\*.proto

View File

@@ -8,7 +8,7 @@ echo "prebuilt binaries for your computer into nanopb-0.4.7"
# the nanopb tool seems to require that the .options file be in the current directory!
cd protobufs
../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated/ -I=../protobufs meshtastic/*.proto
../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated/ -I=../protobufs meshtastic/*.proto --experimental_allow_proto3_optional
# cd ../src/mesh/generated/meshtastic
# sed -i 's/#include "meshtastic/#include "./g' -- *

View File

@@ -0,0 +1,38 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld"
},
"core": "esp32",
"extra_flags": [
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1",
"-DBOARD_HAS_PSRAM"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "bpi_picow_esp32_s3"
},
"connectivity": ["wifi"],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "BPI-PicoW-S3 (8 MB FLASH, 2 MB PSRAM)",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://wiki.banana-pi.org/BPI-PicoW-S3",
"vendor": "BPI"
}

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"
}

View File

@@ -0,0 +1,41 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=0"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "my-esp32s3-diy-oled"
},
"connectivity": ["wifi"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "Clone ESP32-S3-DevKitC-1 v1.1 (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://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html",
"vendor": "Espressif"
}

View File

@@ -0,0 +1,41 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=0"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "my_esp32s3_diy_eink"
},
"connectivity": ["wifi"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "Clone ESP32-S3-DevKitC-1 v1.1 (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://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html",
"vendor": "Espressif"
}

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

@@ -0,0 +1,155 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import re
import subprocess
import sys
from platformio.project.exception import PlatformioException
from platformio.public import (
DeviceMonitorFilterBase,
load_build_metadata,
)
# By design, __init__ is called inside miniterm and we can't pass context to it.
# pylint: disable=attribute-defined-outside-init
IS_WINDOWS = sys.platform.startswith("win")
class Esp32C3ExceptionDecoder(DeviceMonitorFilterBase):
NAME = "esp32_c3_exception_decoder"
PCADDR_PATTERN = re.compile(r'0x4[0-9a-f]{7}', re.IGNORECASE)
def __call__(self):
self.buffer = ""
self.pcaddr_re = self.PCADDR_PATTERN
self.firmware_path = None
self.addr2line_path = None
self.enabled = self.setup_paths()
if self.config.get("env:" + self.environment, "build_type") != "debug":
print(
"""
Please build project in debug configuration to get more details about an exception.
See https://docs.platformio.org/page/projectconf/build_configurations.html
"""
)
return self
def setup_paths(self):
self.project_dir = os.path.abspath(self.project_dir)
try:
data = load_build_metadata(self.project_dir, self.environment)
self.firmware_path = data["prog_path"]
if not os.path.isfile(self.firmware_path):
sys.stderr.write(
"%s: disabling, firmware at %s does not exist, rebuild the project?\n"
% (self.__class__.__name__, self.firmware_path)
)
return False
if self.addr2line_path is None:
cc_path = data.get("cc_path", "")
if "-gcc" in cc_path:
self.addr2line_path = cc_path.replace("-gcc", "-addr2line")
else:
sys.stderr.write(
"%s: disabling, failed to find addr2line.\n"
% self.__class__.__name__
)
return False
if not os.path.isfile(self.addr2line_path):
sys.stderr.write(
"%s: disabling, addr2line at %s does not exist\n"
% (self.__class__.__name__, self.addr2line_path)
)
return False
return True
except PlatformioException as e:
sys.stderr.write(
"%s: disabling, exception while looking for addr2line: %s\n"
% (self.__class__.__name__, e)
)
return False
def rx(self, text):
if not self.enabled:
return text
last = 0
while True:
idx = text.find("\n", last)
if idx == -1:
if len(self.buffer) < 4096:
self.buffer += text[last:]
break
line = text[last:idx]
if self.buffer:
line = self.buffer + line
self.buffer = ""
last = idx + 1
# Output each trace on a separate line below ours
# Logic identical to https://github.com/espressif/esp-idf/blob/master/tools/idf_monitor_base/logger.py#L131
for m in re.finditer(self.pcaddr_re, line):
if m is None:
continue
trace = self.get_backtrace(m)
if len(trace) != "":
text = text[: last] + trace + text[last :]
last += len(trace)
return text
def get_backtrace(self, match):
trace = "\n"
enc = "mbcs" if IS_WINDOWS else "utf-8"
args = [self.addr2line_path, u"-fipC", u"-e", self.firmware_path]
try:
addr = match.group()
output = (
subprocess.check_output(args + [addr])
.decode(enc)
.strip()
)
output = output.replace(
"\n", "\n "
) # newlines happen with inlined methods
output = self.strip_project_dir(output)
# Output the trace in yellow color so that it is easier to spot
trace += "\033[33m=> %s: %s\033[0m\n" % (addr, output)
except subprocess.CalledProcessError as e:
sys.stderr.write(
"%s: failed to call %s: %s\n"
% (self.__class__.__name__, self.addr2line_path, e)
)
return trace
def strip_project_dir(self, trace):
while True:
idx = trace.find(self.project_dir)
if idx == -1:
break
trace = trace[:idx] + trace[idx + len(self.project_dir) + 1 :]
return trace

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,18 +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#da1ede4dfcd91074283b029080759fd744120909 ; 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.6
nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1
jgromes/RadioLib@^5.7.0
; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck
@@ -83,27 +90,28 @@ lib_deps =
${env.lib_deps}
mprograms/QMC5883LCompass@^1.1.1
end2endzone/NonBlockingRTTTL@^1.3.0
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
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 =
adafruit/Adafruit BusIO@^1.11.4
adafruit/Adafruit Unified Sensor@^1.1.4
adafruit/Adafruit Unified Sensor@^1.1.9
adafruit/Adafruit BMP280 Library@^2.6.6
adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BME680 Library@^2.0.1
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
@@ -111,3 +119,6 @@ lib_deps =
adafruit/Adafruit LPS2X@^2.0.4
adafruit/Adafruit SHT31 Library@^2.2.0
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

174
src/AccelerometerThread.h Normal file
View File

@@ -0,0 +1,174 @@
#include "PowerFSM.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
#include "main.h"
#include "power.h"
#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
{
public:
AccelerometerThread(ScanI2C::DeviceType type = ScanI2C::DeviceType::NONE) : OSThread("AccelerometerThread")
{
if (accelerometer_found.port == ScanI2C::I2CPort::NO_I2C) {
LOG_DEBUG("AccelerometerThread disabling due to no sensors found\n");
disable();
return;
}
if (!config.display.wake_on_tap_or_motion && !config.device.double_tap_as_button_press) {
LOG_DEBUG("AccelerometerThread disabling due to no interested configurations\n");
disable();
return;
}
acceleremoter_type = type;
LOG_DEBUG("AccelerometerThread initializing\n");
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);
mpu.setMotionDetectionThreshold(1);
mpu.setMotionDetectionDuration(20);
mpu.setInterruptPinLatch(true); // Keep it latched. Will turn off when reinitialized.
mpu.setInterruptPinPolarity(true);
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.begin(accelerometer_found.address)) {
LOG_DEBUG("LIS3DH initializing\n");
lis.setRange(LIS3DH_RANGE_2_G);
// 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();
}
}
protected:
int32_t runOnce() override
{
canSleep = true; // Assume we should not keep the board awake
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) {
wakeScreen();
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) {
uint8_t click = lis.getClick();
if (!config.device.double_tap_as_button_press) {
wakeScreen();
}
if (config.device.double_tap_as_button_press && (click & 0x20)) {
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;
}
private:
void wakeScreen()
{
if (powerFSM.getState() == &stateDARK) {
LOG_INFO("Tap or motion detected. Turning on screen\n");
powerFSM.trigger(EVENT_INPUT);
}
}
void buttonPress()
{
LOG_DEBUG("Double-tap detected. Firing button press\n");
powerFSM.trigger(EVENT_PRESS);
}
ScanI2C::DeviceType acceleremoter_type;
Adafruit_MPU6050 mpu;
Adafruit_LIS3DH lis;
};
} // 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>
@@ -45,19 +46,19 @@ class ButtonThread : public concurrency::OSThread
ButtonThread() : OSThread("Button")
{
#ifdef BUTTON_PIN
userButton = OneButton(BUTTON_PIN, true, true);
userButton = OneButton(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
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);
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN, FALLING);
wakeOnIrq(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, FALLING);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
@@ -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:
@@ -115,7 +116,9 @@ class ButtonThread : public concurrency::OSThread
{
// LOG_DEBUG("press!\n");
#ifdef BUTTON_PIN
if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) || !moduleConfig.canned_message.enabled) {
if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
moduleConfig.canned_message.inputbroker_pin_press) ||
!moduleConfig.canned_message.enabled) {
powerFSM.trigger(EVENT_PRESS);
}
#endif
@@ -123,17 +126,9 @@ class ButtonThread : public concurrency::OSThread
static void userButtonPressedLong()
{
// LOG_DEBUG("Long press!\n");
#ifdef ARCH_ESP32
screen->adjustBrightness();
#endif
// If user button is held down for 5 seconds, shutdown the device.
if ((millis() - longPressTime > 5 * 1000) && (longPressTime > 0)) {
#ifdef HAS_PMU
if (pmu_found == true) {
setLed(false);
power->shutdown();
}
#elif defined(ARCH_NRF52)
if ((millis() - longPressTime > 5000) && (longPressTime > 0)) {
#if defined(ARCH_NRF52) || defined(ARCH_ESP32)
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
if ((!shutdown_on_long_stop) && (millis() > 30 * 1000)) {
@@ -163,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);
}
@@ -202,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
@@ -34,6 +36,7 @@ bool copyFile(const char *from, const char *to)
f2.write(cbuffer, i);
}
f2.flush();
f2.close();
f1.close();
return true;
@@ -56,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

@@ -13,14 +13,44 @@
#include <WiFi.h>
#endif
#ifndef DELAY_FOREVER
#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:
@@ -104,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
@@ -124,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 {
@@ -143,7 +203,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
}
#else
return 0;
#endif
#endif // BATTERY_PIN
}
/**
@@ -156,8 +216,18 @@ class AnalogBatteryLevel : public HasBatteryLevel
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
/// On some boards we don't have the power management chip (like AXPxxxx)
/// so we use EXT_PWR_DETECT GPIO pin to detect external power source
virtual bool isVbusIn() override
{
#ifdef EXT_PWR_DETECT
// if external powered that pin will be pulled up
if (digitalRead(EXT_PWR_DETECT) == HIGH) {
return true;
}
// if it's not HIGH - check the battery
#endif
return getBattVoltage() > chargingVolt;
}
@@ -189,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;
@@ -198,37 +297,68 @@ Power::Power() : OSThread("Power")
statusHandler = {};
low_voltage_counter = 0;
#ifdef DEBUG_HEAP
lastheap = ESP.getFreeHeap();
lastheap = memGet.getFreeHeap();
#endif
}
bool Power::analogInit()
{
#ifdef EXT_PWR_DETECT
pinMode(EXT_PWR_DETECT, INPUT);
#endif
#ifdef BATTERY_PIN
LOG_DEBUG("Using analog input %d for battery level\n", BATTERY_PIN);
// 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
@@ -256,16 +386,23 @@ void Power::shutdown()
digitalWrite(PIN_EINK_EN, LOW); // power off backlight first
#endif
#ifdef HAS_PMU
LOG_INFO("Shutting down\n");
if (PMU) {
#ifdef HAS_PMU
if (pmu_found == true) {
PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
PMU->shutdown();
}
#elif defined(ARCH_NRF52)
playBeep();
#elif defined(ARCH_NRF52) || defined(ARCH_ESP32)
#ifdef PIN_LED1
ledOff(PIN_LED1);
#endif
#ifdef PIN_LED2
ledOff(PIN_LED2);
#endif
#ifdef PIN_LED3
ledOff(PIN_LED2);
#endif
doDeepSleep(DELAY_FOREVER);
#endif
}
@@ -277,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();
@@ -302,7 +439,7 @@ void Power::readPowerStatus()
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2);
#ifdef DEBUG_HEAP
if (lastheap != ESP.getFreeHeap()) {
if (lastheap != memGet.getFreeHeap()) {
LOG_DEBUG("Threads running:");
int running = 0;
for (int i = 0; i < MAX_THREADS; i++) {
@@ -313,9 +450,9 @@ void Power::readPowerStatus()
}
}
LOG_DEBUG("\n");
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", ESP.getFreeHeap(), ESP.getHeapSize(),
ESP.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
lastheap = ESP.getFreeHeap();
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", memGet.getFreeHeap(), memGet.getHeapSize(),
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
lastheap = memGet.getFreeHeap();
}
#ifdef DEBUG_HEAP_MQTT
if (mqtt) {
@@ -324,41 +461,41 @@ void Power::readPowerStatus()
getMacAddr(dmac); // Get our hardware ID
char mac[18];
sprintf(mac, "!%02x%02x%02x%02x", dmac[2], dmac[3], dmac[4], dmac[5]);
auto newHeap = ESP.getFreeHeap();
std::string heapTopic = "msh/2/heap/" + std::string(mac);
auto newHeap = memGet.getFreeHeap();
std::string heapTopic =
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/heap/") + std::string(mac);
std::string heapString = std::to_string(newHeap);
mqtt->pubSub.publish(heapTopic.c_str(), heapString.c_str(), false);
// auto fragHeap = ESP.getHeapFragmentation();
auto wifiRSSI = WiFi.RSSI();
heapTopic = "msh/2/wifi/" + std::string(mac);
std::string wifiTopic =
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/wifi/") + std::string(mac);
std::string wifiString = std::to_string(wifiRSSI);
mqtt->pubSub.publish(heapTopic.c_str(), wifiString.c_str(), false);
mqtt->pubSub.publish(wifiTopic.c_str(), wifiString.c_str(), false);
}
#endif
#endif
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
#ifdef ARCH_NRF52
// 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++;
LOG_DEBUG("Warning RAK4631 Low voltage counter: %d/10\n", low_voltage_counter);
LOG_DEBUG("Low voltage counter: %d/10\n", low_voltage_counter);
if (low_voltage_counter > 10) {
#ifdef ARCH_NRF52
// We can't trigger deep sleep on NRF52, it's freezing the board
// powerFSM.trigger(EVENT_LOW_BATTERY);
LOG_DEBUG("Low voltage detected, but not triggering deep sleep\n");
#else
LOG_INFO("Low voltage detected, triggering deep sleep\n");
powerFSM.trigger(EVENT_LOW_BATTERY);
#endif
}
} else {
low_voltage_counter = 0;
}
}
#else
// If we have a battery at all and it is less than 10% full, force deep sleep
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
powerFSM.trigger(EVENT_LOW_BATTERY);
#endif
} else {
// No power sensing on this board - tell everyone else we have no idea what is happening
const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
@@ -403,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();
}
@@ -419,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()
@@ -512,52 +651,90 @@ bool Power::axpChipInit()
// Set up the charging voltage
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
// t-beam s3 core
/*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);
/**
* 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);
// GNSS RTC PowerVDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
PMU->enablePowerOutput(XPOWERS_VBACKUP);
// lora radio power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
// ESP32 VDD 3300mV
// ! No need to set, automatically open , Don't close it
// PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
// PMU->setProtectedChannel(XPOWERS_DCDC1);
// m.2 interface
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC3);
// LoRa VDD 3300mV
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);
// 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);
// 6-axis , magnetometer ,bme280 , oled screen power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO1);
// lora radio power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
// sdcard power channle
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
PMU->enablePowerOutput(XPOWERS_BLDO1);
// m.2 interface
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC3);
// PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
// PMU->enablePowerOutput(XPOWERS_DCDC4);
/**
* 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);
// 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);
// 6-axis , magnetometer ,bme280 , oled screen power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO1);
// 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);
@@ -671,4 +848,4 @@ bool Power::axpChipInit()
#else
return false;
#endif
}
}

View File

@@ -26,13 +26,16 @@ static bool isPowered()
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
2) If we detect USB power from the power management chip, we must be getting power externally.
3) On some boards we don't have the power management chip (like AXPxxxx) so we use EXT_PWR_DETECT GPIO pin to detect
external power source (see `isVbusIn()` in `Power.cpp`)
*/
return !isPowerSavingMode && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
}
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));
}
@@ -41,7 +44,7 @@ extern Power *power;
static void shutdownEnter()
{
LOG_INFO("Enter state: SHUTDOWN\n");
LOG_DEBUG("Enter state: SHUTDOWN\n");
power->shutdown();
}
@@ -66,11 +69,11 @@ static void lsIdle()
// Do we have more sleeping to do?
if (secsSlept < config.power.ls_secs) {
// Briefly come out of sleep long enough to blink the led once every few seconds
uint32_t sleepTime = 30;
// If some other service would stall sleep, don't let sleep happen yet
if (doPreflightSleep()) {
// Briefly come out of sleep long enough to blink the led once every few seconds
uint32_t sleepTime = 30;
setLed(false); // Never leave led on while in light sleep
esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL);
@@ -96,12 +99,11 @@ static void lsIdle()
LOG_INFO("wakeCause2 %d\n", wakeCause2);
#ifdef BUTTON_PIN
bool pressed = !digitalRead(BUTTON_PIN);
bool pressed = !digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
#else
bool pressed = false;
#endif
if (pressed) // If we woke because of press, instead generate a PRESS event.
{
if (pressed) { // If we woke because of press, instead generate a PRESS event.
powerFSM.trigger(EVENT_PRESS);
} else {
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
@@ -133,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);
@@ -148,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");
@@ -161,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");
@@ -169,7 +171,11 @@ static void powerEnter()
} else {
screen->setOn(true);
setBluetoothEnable(true);
screen->print("Powered...\n");
// within enter() the function getState() returns the state we came from
if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
strcmp(powerFSM.getState()->name, "DARK") != 0) {
screen->print("Powered...\n");
}
}
}
@@ -186,25 +192,15 @@ static void powerExit()
{
screen->setOn(true);
setBluetoothEnable(true);
screen->print("Unpowered...\n");
if (!isPowered())
screen->print("Unpowered...\n");
}
static void onEnter()
{
LOG_INFO("Enter state: ON\n");
LOG_DEBUG("Enter state: ON\n");
screen->setOn(true);
setBluetoothEnable(true);
static uint32_t lastPingMs;
uint32_t now = millis();
if ((now - lastPingMs) >
30 * 1000) { // if more than a minute since our last press, ask node we are looking at to update their state
if (displayedNodeNum)
service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node
lastPingMs = now;
}
}
static void onIdle()
@@ -222,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");
@@ -257,7 +253,7 @@ void PowerFSM_setup()
// Handle press events - note: we ignore button presses when in API mode
powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateDARK, isPowered() ? &statePOWER : &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press");
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress,
@@ -299,10 +295,10 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
// Show the received text message
powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text"); // restarts the sleep timer
}
// If we are not in statePOWER but get a serial connection, suppress sleep (and keep the screen on) while connected
@@ -330,6 +326,12 @@ void PowerFSM_setup()
powerFSM.add_timed_transition(&stateON, &stateDARK,
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
"Screen-on timeout");
powerFSM.add_timed_transition(&statePOWER, &stateDARK,
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
"Screen-on timeout");
powerFSM.add_timed_transition(&stateDARK, &stateDARK,
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
"Screen-on timeout");
#ifdef ARCH_ESP32
State *lowPowerState = &stateLS;
@@ -350,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

@@ -8,7 +8,7 @@
#define EVENT_WAKE_TIMER 2
// #define EVENT_RECEIVED_PACKET 3
#define EVENT_PACKET_FOR_PHONE 4
#define EVENT_RECEIVED_TEXT_MSG 5
#define EVENT_RECEIVED_MSG 5
// #define EVENT_BOOT 6 // now done with a timed transition
#define EVENT_BLUETOOTH_PAIR 7
#define EVENT_NODEDB_UPDATED 8 // NodeDB has a big enough change that we think you should turn on the screen
@@ -23,6 +23,6 @@
#define EVENT_INPUT 17 // input broker wants something, we need to wake up and enable screen
extern Fsm powerFSM;
extern State statePOWER, stateSERIAL;
extern State stateON, statePOWER, stateSERIAL, stateDARK;
void PowerFSM_setup();

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

@@ -1,5 +1,6 @@
#include "OSThread.h"
#include "configuration.h"
#include "memGet.h"
#include <assert.h>
namespace concurrency
@@ -60,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;
}
@@ -75,12 +79,12 @@ bool OSThread::shouldRun(unsigned long time)
void OSThread::run()
{
#ifdef DEBUG_HEAP
auto heap = ESP.getFreeHeap();
auto heap = memGet.getFreeHeap();
#endif
currentThread = this;
auto newDelay = runOnce();
#ifdef DEBUG_HEAP
auto newHeap = ESP.getFreeHeap();
auto newHeap = memGet.getFreeHeap();
if (newHeap < heap)
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------\n", ThreadName.c_str(), heap, newHeap, newHeap - heap);
if (heap < newHeap)

View File

@@ -82,7 +82,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// #define DISABLE_NTP
// Disable the welcome screen and allow
//#define DISABLE_WELCOME_UNSET
// #define DISABLE_WELCOME_UNSET
// -----------------------------------------------------------------------------
// OLED & Input
@@ -93,13 +93,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// The SH1106 controller is almost, but not quite, the same as SSD1306
// Define this if you know you have that controller or your "SSD1306" misbehaves.
//#define USE_SH1106
// #define USE_SH1106
// 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
@@ -118,6 +119,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define SHT31_ADDR 0x44
#define PMSA0031_ADDR 0x12
// -----------------------------------------------------------------------------
// ACCELEROMETER
// -----------------------------------------------------------------------------
#define MPU6050_ADDR 0x68
#define LIS3DH_ADR 0x18
#define BMA423_ADDR 0x19
// -----------------------------------------------------------------------------
// LED
// -----------------------------------------------------------------------------
#define NCP5623_ADDR 0x38
// -----------------------------------------------------------------------------
// Security
// -----------------------------------------------------------------------------
@@ -161,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
@@ -182,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

76
src/detect/ScanI2C.cpp Normal file
View File

@@ -0,0 +1,76 @@
#include "ScanI2C.h"
const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress();
const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE);
ScanI2C::ScanI2C() = default;
void ScanI2C::scanPort(ScanI2C::I2CPort port) {}
void ScanI2C::setSuppressScreen()
{
shouldSuppressScreen = true;
}
ScanI2C::FoundDevice ScanI2C::firstScreen() const
{
// Allow to override the scanner results for screen
if (shouldSuppressScreen)
return DEVICE_NONE;
ScanI2C::DeviceType types[] = {SCREEN_SSD1306, SCREEN_SH1106, SCREEN_ST7567, SCREEN_UNKNOWN};
return firstOfOrNONE(4, types);
}
ScanI2C::FoundDevice ScanI2C::firstRTC() const
{
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563};
return firstOfOrNONE(2, types);
}
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, RAK14004};
return firstOfOrNONE(3, types);
}
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
{
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423};
return firstOfOrNONE(3, types);
}
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const
{
return DEVICE_NONE;
}
bool ScanI2C::exists(ScanI2C::DeviceType) const
{
return false;
}
ScanI2C::FoundDevice ScanI2C::firstOfOrNONE(size_t count, ScanI2C::DeviceType *types) const
{
return DEVICE_NONE;
}
size_t ScanI2C::countDevices() const
{
return 0;
}
ScanI2C::DeviceAddress::DeviceAddress(ScanI2C::I2CPort port, uint8_t address) : port(port), address(address) {}
ScanI2C::DeviceAddress::DeviceAddress() : DeviceAddress(I2CPort::NO_I2C, 0) {}
bool ScanI2C::DeviceAddress::operator<(const ScanI2C::DeviceAddress &other) const
{
return
// If this one has no port and other has a port
(port == NO_I2C && other.port != NO_I2C)
// if both have a port and this one's address is lower
|| (port != NO_I2C && other.port != NO_I2C && (address < other.address));
}
ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {}

102
src/detect/ScanI2C.h Normal file
View File

@@ -0,0 +1,102 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
class ScanI2C
{
public:
typedef enum DeviceType {
NONE,
SCREEN_SSD1306,
SCREEN_SH1106,
SCREEN_UNKNOWN, // has the same address as the two above but does not respond to the same commands
SCREEN_ST7567,
ATECC608B,
RTC_RV3028,
RTC_PCF8563,
CARDKB,
TDECKKB,
RAK14004,
PMU_AXP192_AXP2101,
BME_680,
BME_280,
BMP_280,
INA260,
INA219,
MCP9808,
SHT31,
SHTC3,
LPS22HB,
QMC6310,
QMI8658,
QMC5883L,
PMSA0031,
MPU6050,
LIS3DH,
BMA423,
#ifdef HAS_NCP5623
NCP5623,
#endif
} DeviceType;
// typedef uint8_t DeviceAddress;
typedef enum I2CPort {
NO_I2C,
WIRE,
WIRE1,
} I2CPort;
typedef struct DeviceAddress {
I2CPort port;
uint8_t address;
explicit DeviceAddress(I2CPort port, uint8_t address);
DeviceAddress();
bool operator<(const DeviceAddress &other) const;
} DeviceAddress;
static const DeviceAddress ADDRESS_NONE;
typedef uint8_t RegisterAddress;
typedef struct FoundDevice {
DeviceType type;
DeviceAddress address;
explicit FoundDevice(DeviceType = DeviceType::NONE, DeviceAddress = ADDRESS_NONE);
} FoundDevice;
static const FoundDevice DEVICE_NONE;
public:
ScanI2C();
virtual void scanPort(ScanI2C::I2CPort);
/*
* A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it.
*/
void setSuppressScreen();
FoundDevice firstScreen() const;
FoundDevice firstRTC() const;
FoundDevice firstKeyboard() const;
FoundDevice firstAccelerometer() const;
virtual FoundDevice find(DeviceType) const;
virtual bool exists(DeviceType) const;
virtual size_t countDevices() const;
protected:
virtual FoundDevice firstOfOrNONE(size_t, DeviceType[]) const;
private:
bool shouldSuppressScreen = false;
};

View File

@@ -0,0 +1,311 @@
#include "ScanI2CTwoWire.h"
#include "concurrency/LockGuard.h"
#include "configuration.h"
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "main.h" // atecc
#endif
// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp
#ifndef XPOWERS_AXP192_AXP2101_ADDRESS
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34
#endif
ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
return exists(type) ? ScanI2C::FoundDevice(type, deviceAddresses.at(type)) : DEVICE_NONE;
}
bool ScanI2CTwoWire::exists(ScanI2C::DeviceType type) const
{
return deviceAddresses.find(type) != deviceAddresses.end();
}
ScanI2C::FoundDevice ScanI2CTwoWire::firstOfOrNONE(size_t count, DeviceType types[]) const
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
for (size_t k = 0; k < count; k++) {
ScanI2C::DeviceType current = types[k];
if (exists(current)) {
return ScanI2C::FoundDevice(current, deviceAddresses.at(current));
}
}
return DEVICE_NONE;
}
ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const
{
TwoWire *i2cBus = fetchI2CBus(addr);
uint8_t r = 0;
uint8_t r_prev = 0;
uint8_t c = 0;
ScanI2C::DeviceType o_probe = ScanI2C::DeviceType::SCREEN_UNKNOWN;
do {
r_prev = r;
i2cBus->beginTransmission(addr.address);
i2cBus->write((uint8_t)0x00);
i2cBus->endTransmission();
i2cBus->requestFrom((int)addr.address, 1);
if (i2cBus->available()) {
r = i2cBus->read();
}
r &= 0x0f;
if (r == 0x08 || r == 0x00) {
LOG_INFO("sh1106 display found\n");
o_probe = SCREEN_SH1106; // SH1106
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
LOG_INFO("ssd1306 display found\n");
o_probe = SCREEN_SSD1306; // SSD1306
}
c++;
} while ((r != r_prev) && (c < 4));
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
return o_probe;
}
void ScanI2CTwoWire::printATECCInfo() const
{
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
atecc.readConfigZone(false);
LOG_DEBUG("ATECC608B Serial Number: ");
for (int i = 0; i < 9; i++) {
LOG_DEBUG("%02x", atecc.serialNumber[i]);
}
LOG_DEBUG(", Rev Number: ");
for (int i = 0; i < 4; i++) {
LOG_DEBUG("%02x", atecc.revisionNumber[i]);
}
LOG_DEBUG("\n");
LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked");
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
if (atecc.generatePublicKey() == false) {
LOG_DEBUG("ATECC608B Error generating public key\n");
} else {
LOG_DEBUG("ATECC608B Public Key: ");
for (int i = 0; i < 64; i++) {
LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]);
}
LOG_DEBUG("\n");
}
}
#endif
}
uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation &registerLocation,
ScanI2CTwoWire::ResponseWidth responseWidth) const
{
uint16_t value = 0x00;
TwoWire *i2cBus = fetchI2CBus(registerLocation.i2cAddress);
i2cBus->beginTransmission(registerLocation.i2cAddress.address);
i2cBus->write(registerLocation.registerAddress);
i2cBus->endTransmission();
delay(20);
i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth);
LOG_DEBUG("Wire.available() = %d\n", i2cBus->available());
if (i2cBus->available() == 2) {
// Read MSB, then LSB
value = (uint16_t)i2cBus->read() << 8;
value |= i2cBus->read();
} else if (i2cBus->available()) {
value = i2cBus->read();
}
return value;
}
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
case ADDR: \
LOG_INFO(__VA_ARGS__); \
type = T; \
break;
void ScanI2CTwoWire::scanPort(I2CPort port)
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
LOG_DEBUG("Scanning for i2c devices on port %d\n", port);
uint8_t err;
DeviceAddress addr(port, 0x00);
uint16_t registerValue = 0x00;
ScanI2C::DeviceType type;
TwoWire *i2cBus;
#ifdef RV3028_RTC
Melopero_RV3028 rtc;
#endif
#ifdef I2C_SDA1
if (port == I2CPort::WIRE1) {
i2cBus = &Wire1;
} else {
#endif
i2cBus = &Wire;
#ifdef I2C_SDA1
}
#endif
for (addr.address = 1; addr.address < 127; addr.address++) {
i2cBus->beginTransmission(addr.address);
err = i2cBus->endTransmission();
type = NONE;
if (err == 0) {
LOG_DEBUG("I2C device found at address 0x%x\n", addr.address);
switch (addr.address) {
case SSD1306_ADDRESS:
type = probeOLED(addr);
break;
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
case ATECC608B_ADDR:
type = ATECC608B;
if (atecc.begin(addr.address) == true) {
LOG_INFO("ATECC608B initialized\n");
} else {
LOG_WARN("ATECC608B initialization failed\n");
}
printATECCInfo();
break;
#endif
#ifdef RV3028_RTC
case RV3028_RTC:
// foundDevices[addr] = RTC_RV3028;
type = RTC_RV3028;
LOG_INFO("RV3028 RTC found\n");
rtc.initI2C(*i2cBus);
rtc.writeToRegister(0x35, 0x07); // no Clkout
rtc.writeToRegister(0x37, 0xB4);
break;
#endif
#ifdef PCF8563_RTC
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563 RTC found\n")
#endif
case CARDKB_ADDR:
// Do we have the RAK14006 instead?
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1);
if (registerValue == 0x02) {
// KEYPAD_VERSION
LOG_INFO("RAK14004 found\n");
type = RAK14004;
} else {
LOG_INFO("m5 cardKB found\n");
type = CARDKB;
}
break;
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
case BME_ADDR:
case BME_ADDR_ALTERNATE:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID
switch (registerValue) {
case 0x61:
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BME_680;
break;
case 0x60:
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BME_280;
break;
default:
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BMP_280;
}
break;
case INA_ADDR:
case INA_ADDR_ALTERNATE:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
if (registerValue == 0x5449) {
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = INA260;
} else { // Assume INA219 if INA260 ID is not found
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = INA219;
}
break;
case MCP9808_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
if (registerValue == 0x0400) {
type = MCP9808;
LOG_INFO("MCP9808 sensor found\n");
} else {
type = LIS3DH;
LOG_INFO("LIS3DH accelerometer found\n");
}
break;
SCAN_SIMPLE_CASE(SHT31_ADDR, SHT31, "SHT31 sensor found\n")
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found\n")
case LPS22HB_ADDR_ALT:
SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB sensor found\n")
SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310 Highrate 3-Axis magnetic sensor found\n")
SCAN_SIMPLE_CASE(QMI8658_ADDR, QMI8658, "QMI8658 Highrate 6-Axis inertial measurement sensor found\n")
SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found\n")
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);
}
} else if (err == 4) {
LOG_ERROR("Unknown error at address 0x%x\n", addr);
}
// Check if a type was found for the enumerated device - save, if so
if (type != NONE) {
deviceAddresses[type] = addr;
foundDevices[addr] = type;
}
}
}
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
{
if (address.port == ScanI2C::I2CPort::WIRE) {
return &Wire;
} else {
#ifdef I2C_SDA1
return &Wire1;
#else
return &Wire;
#endif
}
}
size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
}

View File

@@ -0,0 +1,56 @@
#pragma once
#include <map>
#include <memory>
#include <stddef.h>
#include <stdint.h>
#include <Wire.h>
#include "ScanI2C.h"
#include "../concurrency/Lock.h"
class ScanI2CTwoWire : public ScanI2C
{
public:
void scanPort(ScanI2C::I2CPort) override;
ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override;
bool exists(ScanI2C::DeviceType) const override;
size_t countDevices() const override;
protected:
FoundDevice firstOfOrNONE(size_t, DeviceType[]) const override;
private:
typedef struct RegisterLocation {
DeviceAddress i2cAddress;
RegisterAddress registerAddress;
RegisterLocation(DeviceAddress deviceAddress, RegisterAddress registerAddress)
: i2cAddress(deviceAddress), registerAddress(registerAddress)
{
}
} RegisterLocation;
typedef uint8_t ResponseWidth;
std::map<ScanI2C::DeviceAddress, ScanI2C::DeviceType> foundDevices;
// note: prone to overwriting if multiple devices of a type are added at different addresses (rare?)
std::map<ScanI2C::DeviceType, ScanI2C::DeviceAddress> deviceAddresses;
concurrency::Lock lock;
void printATECCInfo() const;
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const;
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
};

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

@@ -1,237 +0,0 @@
#include "../configuration.h"
#include "../main.h"
#include "mesh/generated/meshtastic/telemetry.pb.h"
#include <Wire.h>
// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp
#ifndef XPOWERS_AXP192_AXP2101_ADDRESS
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34
#endif
#if HAS_WIRE
void printATECCInfo()
{
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
atecc.readConfigZone(false);
LOG_DEBUG("ATECC608B Serial Number: ");
for (int i = 0; i < 9; i++) {
LOG_DEBUG("%02x", atecc.serialNumber[i]);
}
LOG_DEBUG(", Rev Number: ");
for (int i = 0; i < 4; i++) {
LOG_DEBUG("%02x", atecc.revisionNumber[i]);
}
LOG_DEBUG("\n");
LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked");
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
if (atecc.generatePublicKey() == false) {
LOG_DEBUG("ATECC608B Error generating public key\n");
} else {
LOG_DEBUG("ATECC608B Public Key: ");
for (int i = 0; i < 64; i++) {
LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]);
}
LOG_DEBUG("\n");
}
}
#endif
}
uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length)
{
uint16_t value = 0x00;
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
delay(20);
Wire.requestFrom(address, length);
LOG_DEBUG("Wire.available() = %d\n", Wire.available());
if (Wire.available() == 2) {
// Read MSB, then LSB
value = (uint16_t)Wire.read() << 8;
value |= Wire.read();
} else if (Wire.available()) {
value = Wire.read();
}
return value;
}
uint8_t oled_probe(byte addr)
{
uint8_t r = 0;
uint8_t r_prev = 0;
uint8_t c = 0;
uint8_t o_probe = 0;
do {
r_prev = r;
Wire.beginTransmission(addr);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom((int)addr, 1);
if (Wire.available()) {
r = Wire.read();
}
r &= 0x0f;
if (r == 0x08 || r == 0x00) {
o_probe = 2; // SH1106
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
o_probe = 1; // SSD1306
}
c++;
} while ((r != r_prev) && (c < 4));
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
return o_probe;
}
void scanI2Cdevice()
{
byte err, addr;
uint16_t registerValue = 0x00;
int nDevices = 0;
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
err = Wire.endTransmission();
if (err == 0) {
LOG_DEBUG("I2C device found at address 0x%x\n", addr);
nDevices++;
if (addr == SSD1306_ADDRESS) {
screen_found = addr;
screen_model = oled_probe(addr);
if (screen_model == 1) {
LOG_INFO("ssd1306 display found\n");
} else if (screen_model == 2) {
LOG_INFO("sh1106 display found\n");
} else {
LOG_INFO("unknown display found\n");
}
}
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
if (addr == ATECC608B_ADDR) {
keystore_found = addr;
if (atecc.begin(keystore_found) == true) {
LOG_INFO("ATECC608B initialized\n");
} else {
LOG_WARN("ATECC608B initialization failed\n");
}
printATECCInfo();
}
#endif
#ifdef RV3028_RTC
if (addr == RV3028_RTC) {
rtc_found = addr;
LOG_INFO("RV3028 RTC found\n");
Melopero_RV3028 rtc;
rtc.initI2C();
rtc.writeToRegister(0x35, 0x07); // no Clkout
rtc.writeToRegister(0x37, 0xB4);
}
#endif
#ifdef PCF8563_RTC
if (addr == PCF8563_RTC) {
rtc_found = addr;
LOG_INFO("PCF8563 RTC found\n");
}
#endif
if (addr == CARDKB_ADDR) {
cardkb_found = addr;
// Do we have the RAK14006 instead?
registerValue = getRegisterValue(addr, 0x04, 1);
if (registerValue == 0x02) { // KEYPAD_VERSION
LOG_INFO("RAK14004 found\n");
kb_model = 0x02;
} else {
LOG_INFO("m5 cardKB found\n");
kb_model = 0x00;
}
}
if (addr == ST7567_ADDRESS) {
screen_found = addr;
LOG_INFO("st7567 display found\n");
}
#ifdef HAS_PMU
if (addr == XPOWERS_AXP192_AXP2101_ADDRESS) {
pmu_found = true;
LOG_INFO("axp192/axp2101 PMU found\n");
}
#endif
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
if (registerValue == 0x61) {
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME680] = addr;
} else if (registerValue == 0x60) {
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME280] = addr;
} else {
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BMP280] = addr;
}
}
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xFE, 2);
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
if (registerValue == 0x5449) {
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] = addr;
} else { // Assume INA219 if INA260 ID is not found
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] = addr;
}
}
if (addr == MCP9808_ADDR) {
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MCP9808] = addr;
LOG_INFO("MCP9808 sensor found\n");
}
if (addr == SHT31_ADDR) {
LOG_INFO("SHT31 sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHT31] = addr;
}
if (addr == SHTC3_ADDR) {
LOG_INFO("SHTC3 sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHTC3] = addr;
}
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
LOG_INFO("LPS22HB sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_LPS22] = addr;
}
// High rate sensors, will be processed internally
if (addr == QMC6310_ADDR) {
LOG_INFO("QMC6310 Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC6310] = addr;
}
if (addr == QMI8658_ADDR) {
LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMI8658] = addr;
}
if (addr == QMC5883L_ADDR) {
LOG_INFO("QMC5883L Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC5883L] = addr;
}
if (addr == PMSA0031_ADDR) {
LOG_INFO("PMSA0031 air quality sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I] = addr;
}
} else if (err == 4) {
LOG_ERROR("Unknow error at address 0x%x\n", addr);
}
}
if (nDevices == 0)
LOG_INFO("No I2C devices found\n");
else
LOG_INFO("%i I2C devices found\n", nDevices);
}
#else
void scanI2Cdevice() {}
#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

@@ -1,5 +1,6 @@
#include "RTC.h"
#include "configuration.h"
#include "detect/ScanI2C.h"
#include "main.h"
#include <sys/time.h>
#include <time.h>
@@ -18,12 +19,16 @@ 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 == RV3028_RTC) {
if (rtc_found.address == RV3028_RTC) {
uint32_t now = millis();
Melopero_RV3028 rtc;
#ifdef I2C_SDA1
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C();
#endif
tm t;
t.tm_year = rtc.getYear() - 1900;
t.tm_mon = rtc.getMonth() - 1;
@@ -41,14 +46,16 @@ void readFromRTC()
}
}
#elif defined(PCF8563_RTC)
if (rtc_found == PCF8563_RTC) {
if (rtc_found.address == PCF8563_RTC) {
uint32_t now = millis();
PCF8563_Class rtc;
#ifdef RTC_USE_WIRE1
rtc.begin(Wire1);
#ifdef I2C_SDA1
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.begin();
#endif
auto tc = rtc.getDateTime();
tm t;
t.tm_year = tc.year - 1900;
@@ -103,19 +110,24 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
// If this platform has a setable RTC, set it
#ifdef RV3028_RTC
if (rtc_found == RV3028_RTC) {
if (rtc_found.address == RV3028_RTC) {
Melopero_RV3028 rtc;
#ifdef I2C_SDA1
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C();
#endif
tm *t = localtime(&tv->tv_sec);
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
}
#elif defined(PCF8563_RTC)
if (rtc_found == PCF8563_RTC) {
if (rtc_found.address == PCF8563_RTC) {
PCF8563_Class rtc;
#ifdef RTC_USE_WIRE1
rtc.begin(Wire1);
#ifdef I2C_SDA1
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.begin();
#endif

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,17 @@
#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
#define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
#elif defined(PCA10059)
@@ -37,11 +45,14 @@
// 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;
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model)
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{
#if defined(TTGO_T_ECHO)
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
@@ -59,6 +70,13 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model
// 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);
#elif defined(PCA10059)
// GxEPD2_420_M01
@@ -69,6 +87,11 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model
// M5Stack_CoreInk 200x200
// 1.54 inch 200x200 - GxEPD2_154_M09
setGeometry(GEOMETRY_RAWMODE, EPD_HEIGHT, EPD_WIDTH);
#elif defined(my)
// GxEPD2_290_T5D
setGeometry(GEOMETRY_RAWMODE, 296, 128);
LOG_DEBUG("GEOMETRY_RAWMODE, 296, 128\n");
#endif
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
@@ -97,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);
@@ -109,7 +132,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
#if defined(TTGO_T_ECHO)
// ePaper.Reset(); // wake the screen from sleep
adafruitDisplay->display(false); // FIXME, use partial update mode
#elif defined(RAK4630)
#elif defined(RAK4630) || defined(MAKERPYTHON)
// RAK14000 2.13 inch b/w 250x122 actually now does support partial updates
@@ -125,6 +148,10 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
#elif defined(PCA10059) || defined(M5_COREINK)
adafruitDisplay->nextPage();
#elif defined(PRIVATE_HW) || defined(my)
adafruitDisplay->nextPage();
#endif
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
@@ -184,7 +211,7 @@ bool EInkDisplay::connect()
adafruitDisplay->init();
adafruitDisplay->setRotation(3);
}
#elif defined(RAK4630)
#elif defined(RAK4630) || defined(MAKERPYTHON)
{
if (eink_found) {
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
@@ -202,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);
@@ -216,6 +253,14 @@ bool EInkDisplay::connect()
adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
adafruitDisplay->setRotation(0);
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
#elif defined(my)
{
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);
adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
adafruitDisplay->setRotation(1);
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
}
#endif
// adafruitDisplay->setFullWindow();

View File

@@ -22,7 +22,7 @@ class EInkDisplay : public OLEDDisplay
/* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/
EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model);
EInkDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
// Write the buffer to the display memory (for eink we only do this occasionally)
virtual void display(void) override;

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

@@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Screen.h"
#include "configuration.h"
#if HAS_SCREEN
#include <OLEDDisplay.h>
@@ -26,10 +27,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "Screen.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)
@@ -348,20 +350,18 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
/// Draw the last text message we received
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
displayedNodeNum = 0; // Not currently showing a node pane
display->setTextAlignment(TEXT_ALIGN_LEFT);
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;
@@ -370,13 +370,11 @@ static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
/// Draw the last text message we received
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
displayedNodeNum = 0; // Not currently showing a node pane
// the max length of this buffer is much longer than we can possibly print
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);
@@ -408,7 +406,44 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
}
/// Draw a series of fields in a column, wrapping to multiple colums if needed
/// Draw the last waypoint we received
static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
static char tempBuf[237];
meshtastic_MeshPacket &mp = devicestate.rx_waypoint;
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
}
uint32_t seconds = sinceReceived(&mp);
uint32_t minutes = seconds / 60;
uint32_t hours = minutes / 60;
uint32_t days = hours / 24;
if (config.display.heading_bold) {
display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s",
screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
(node && node->has_user) ? node->user.short_name : "???");
}
display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
(node && node->has_user) ? node->user.short_name : "???");
display->setColor(WHITE);
meshtastic_Waypoint scratch;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
snprintf(tempBuf, sizeof(tempBuf), "Received waypoint: %s", scratch.name);
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
}
}
/// 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
@@ -458,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);
@@ -678,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;
@@ -766,17 +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);
}
displayedNodeNum = n->num;
}
meshtastic_NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex);
meshtastic_NodeInfoLite *node = nodeDB.getMeshNodeByIndex(nodeIndex);
display->setFont(FONT_SMALL);
@@ -809,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;
@@ -824,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));
@@ -860,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);
@@ -886,13 +918,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// }
// }
// #else
Screen::Screen(uint8_t address, int sda, int scl)
: OSThread("Screen"), cmdQueue(32),
dispdev(address, sda, scl,
screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 ? GEOMETRY_128_128 : GEOMETRY_128_64),
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32),
dispdev(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE),
ui(&dispdev)
{
address_found = address;
cmdQueue.setReader(this);
}
// #endif
@@ -919,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;
@@ -927,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;
@@ -940,9 +976,11 @@ void Screen::setup()
useDisplay = true;
#ifdef AutoOLEDWire_h
if (screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107)
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1106;
dispdev.setDetected(screen_model);
dispdev.setDetected(model);
#endif
#ifdef USE_SH1107_128_64
dispdev.setSubtype(7);
#endif
// Initialising the UI will init the display too.
@@ -1007,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);
@@ -1090,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;
@@ -1177,7 +1227,7 @@ void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiStat
* it is expected that this will be used during the boot phase */
void Screen::setSSLFrames()
{
if (address_found) {
if (address_found.address) {
// LOG_DEBUG("showing SSL frames\n");
static FrameCallback sslFrames[] = {drawSSLScreen};
ui.setFrames(sslFrames, 1);
@@ -1189,7 +1239,7 @@ void Screen::setSSLFrames()
* it is expected that this will be used during the boot phase */
void Screen::setWelcomeFrames()
{
if (address_found) {
if (address_found.address) {
// LOG_DEBUG("showing Welcome frames\n");
ui.disableAllIndicators();
@@ -1207,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 = nodeStatus->getNumTotal();
if (numnodes > 0)
numnodes--;
size_t numMeshNodes = nodeDB.getNumMeshNodes();
if (numMeshNodes > 0)
numMeshNodes--;
size_t numframes = 0;
@@ -1230,17 +1282,21 @@ 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
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
normalFrames[numframes++] = drawTextMessageFrame;
}
// If we have a waypoint - show it next, unless it's a phone message and we aren't using any special modules
if (devicestate.has_rx_waypoint && shouldDrawMessage(&devicestate.rx_waypoint)) {
normalFrames[numframes++] = drawWaypointFrame;
}
// 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;
@@ -1377,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
@@ -1393,8 +1471,6 @@ void Screen::setFastFramerate()
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text
@@ -1451,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,
@@ -1461,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,
@@ -1473,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,
@@ -1502,8 +1578,6 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
#if HAS_WIFI
const char *wifiName = config.network.wifi_ssid;
displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text
@@ -1634,8 +1708,6 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text
@@ -1762,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)
@@ -1820,6 +1892,21 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
return 0;
}
} // namespace graphics
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();
}
}
#endif // HAS_SCREEN
return 0;
}
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
#endif // HAS_SCREEN

View File

@@ -2,6 +2,10 @@
#include "configuration.h"
#include "detect/ScanI2C.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include <OLEDDisplay.h>
#if !HAS_SCREEN
#include "power.h"
namespace graphics
@@ -10,7 +14,7 @@ namespace graphics
class Screen
{
public:
explicit Screen(char) {}
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
void onPress() {}
void setup() {}
void setOn(bool) {}
@@ -21,10 +25,10 @@ class Screen
void startBluetoothPinScreen(uint32_t pin) {}
void stopBluetoothPinScreen() {}
void startRebootScreen() {}
void startShutdownScreen() {}
void startFirmwareUpdateScreen() {}
};
} // namespace graphics
#else
#include <cstring>
@@ -34,7 +38,7 @@ class Screen
#ifdef USE_ST7567
#include <ST7567Wire.h>
#elif defined(USE_SH1106) || defined(USE_SH1107)
#elif defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
#include <SH1106Wire.h>
#elif defined(USE_SSD1306)
#include <SSD1306Wire.h>
@@ -49,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>
@@ -114,14 +119,18 @@ 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(uint8_t address, int sda = -1, int scl = -1);
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
Screen(const Screen &) = delete;
Screen &operator=(const Screen &) = delete;
uint8_t address_found;
ScanI2C::DeviceAddress address_found;
meshtastic_Config_DisplayConfig_OledType model;
OLEDDISPLAY_GEOMETRY geometry;
/// Initializes the UI, turns on the display, starts showing boot screen.
//
@@ -146,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();
@@ -295,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();
@@ -337,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();
@@ -370,11 +385,11 @@ class Screen : public concurrency::OSThread
/// Display device
#if defined(USE_SH1106) || defined(USE_SH1107)
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
SH1106Wire dispdev;
#elif defined(USE_SSD1306)
SSD1306Wire dispdev;
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
TFTDisplay dispdev;
#elif defined(USE_EINK)
EInkDisplay dispdev;
@@ -388,4 +403,4 @@ class Screen : public concurrency::OSThread
};
} // namespace graphics
#endif
#endif

View File

@@ -1,14 +1,235 @@
#include "configuration.h"
#if defined(ST7735_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
#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
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model)
#endif
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER)
#include "SPILock.h"
#include "TFTDisplay.h"
#include <SPI.h>
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{
#ifdef SCREEN_ROTATE
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);
@@ -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?
@@ -18,11 +17,15 @@ class TFTDisplay : public OLEDDisplay
/* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/
TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model);
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
// 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

@@ -1,7 +1,8 @@
#pragma once
#include "InputBroker.h"
#include "SinglePortModule.h" // TODO: what header file to include?
#include "concurrency/OSThread.h"
#include "mesh/NodeDB.h"
enum RotaryEncoderInterruptBaseStateType { ROTARY_EVENT_OCCURRED, ROTARY_EVENT_CLEARED };

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

@@ -1,7 +1,7 @@
#pragma once
#include "InputBroker.h"
#include "SinglePortModule.h" // TODO: what header file to include?
#include "mesh/NodeDB.h"
class UpDownInterruptBase : public Observable<const InputEvent *>
{

View File

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

View File

@@ -1,8 +1,9 @@
#include "kbI2cBase.h"
#include "configuration.h"
#include <Wire.h>
extern uint8_t cardkb_found;
#include "configuration.h"
#include "detect/ScanI2C.h"
extern ScanI2C::DeviceAddress cardkb_found;
extern uint8_t kb_model;
KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
@@ -10,43 +11,64 @@ KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
this->_originName = name;
}
uint8_t read_from_14004(uint8_t reg, uint8_t *data, uint8_t length)
uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t length)
{
uint8_t readflag = 0;
Wire.beginTransmission(CARDKB_ADDR);
Wire.write(reg);
Wire.endTransmission(); // stop transmitting
i2cBus->beginTransmission(CARDKB_ADDR);
i2cBus->write(reg);
i2cBus->endTransmission(); // stop transmitting
delay(20);
Wire.requestFrom(CARDKB_ADDR, (int)length);
i2cBus->requestFrom(CARDKB_ADDR, (int)length);
int i = 0;
while (Wire.available()) // slave may send less than requested
while (i2cBus->available()) // slave may send less than requested
{
data[i++] = Wire.read(); // receive a byte as a proper uint8_t
data[i++] = i2cBus->read(); // receive a byte as a proper uint8_t
readflag = 1;
}
return readflag;
}
void write_to_14004(uint8_t reg, uint8_t data)
// Unused for now - flagging it off
#if 0
void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
{
Wire.beginTransmission(CARDKB_ADDR);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission(); // stop transmitting
i2cBus->beginTransmission(CARDKB_ADDR);
i2cBus->write(reg);
i2cBus->write(data);
i2cBus->endTransmission(); // stop transmitting
}
#endif
int32_t KbI2cBase::runOnce()
{
if (cardkb_found != CARDKB_ADDR) {
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
// Input device is not detected.
return INT32_MAX;
}
if (!i2cBus) {
switch (cardkb_found.port) {
case ScanI2C::WIRE1:
#ifdef I2C_SDA1
LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
i2cBus = &Wire1;
break;
#endif
case ScanI2C::WIRE:
LOG_DEBUG("Using I2C Bus 0 (the first one)\n");
i2cBus = &Wire;
break;
case ScanI2C::NO_I2C:
default:
i2cBus = 0;
}
}
if (kb_model == 0x02) {
// RAK14004
uint8_t rDataBuf[8] = {0};
uint8_t PrintDataBuf = 0;
if (read_from_14004(0x01, rDataBuf, 0x04) == 1) {
if (read_from_14004(i2cBus, 0x01, rDataBuf, 0x04) == 1) {
for (uint8_t aCount = 0; aCount < 0x04; aCount++) {
for (uint8_t bCount = 0; bCount < 0x04; bCount++) {
if (((rDataBuf[aCount] >> bCount) & 0x01) == 0x01) {
@@ -63,12 +85,12 @@ int32_t KbI2cBase::runOnce()
e.kbchar = PrintDataBuf;
this->notifyObservers(&e);
}
} else {
// m5 cardkb
Wire.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 (Wire.available()) {
char c = Wire.read();
while (i2cBus->available()) {
char c = i2cBus->read();
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.source = this->_originName;
@@ -110,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

@@ -1,7 +1,8 @@
#pragma once
#include "InputBroker.h"
#include "SinglePortModule.h" // TODO: what header file to include?
#include "Wire.h"
#include "concurrency/OSThread.h"
class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OSThread
{
@@ -13,4 +14,6 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
private:
const char *_originName;
TwoWire *i2cBus = 0;
};

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