Compare commits

...

320 Commits

Author SHA1 Message Date
Ben Meadors
090e1660fe Merge pull request #2053 from meshtastic/upstream-heltec
Move to upstream espressif arduino
2022-12-21 07:47:27 -06:00
Ben Meadors
92c9b34d4f Copy pasta 2022-12-21 07:46:59 -06:00
Ben Meadors
3f50371ff3 Merge branch 'master' into upstream-heltec 2022-12-21 07:45:18 -06:00
Ben Meadors
815f9bfc5f Move to upstream espressif arduino 2022-12-21 07:41:26 -06:00
Thomas Göttgens
86ff23d13c Merge pull request #2051 from meshtastic/master-next
moving a lot of stuff from develop into Master
2022-12-21 14:35:19 +01:00
Thomas Göttgens
201b786f77 fix RAK build 2022-12-21 14:06:02 +01:00
Thomas Göttgens
755c0b7008 use nanopb 0.4.7 2022-12-21 13:37:38 +01:00
Thomas Göttgens
7396d0f241 Cherry Picking Stuff from develop... 2022-12-21 13:36:38 +01:00
Thomas Göttgens
220859d0aa Merge pull request #2019 from code8buster/gps-toggle-final
Adds a flag to turn the GPS power rail off entirely on tbeam
2022-12-21 13:28:32 +01:00
Thomas Göttgens
941786669b fix compiler warnings 2022-12-21 13:28:29 +01:00
Thomas Göttgens
4eb620d47b Heap Debug: only show if delta occurs 2022-12-21 13:28:29 +01:00
Thomas Göttgens
9794995d7a fix building DIY-1 target 2022-12-21 13:28:29 +01:00
Thomas Göttgens
055146602a support ESP32-S2 CPUs
Note: these don't have Bluetooth and only a single physical core.
2022-12-21 13:28:28 +01:00
Thomas Göttgens
86d7860d86 made a nice PTT/RECV screen for audio module. And cleaned up screen graphics a bit. 2022-12-21 13:28:28 +01:00
Thomas Göttgens
0f2d0d1f07 change on screen graphics to support bicolor screens 2022-12-21 13:28:28 +01:00
Thomas Göttgens
ab6a5a5e07 if we get different frames than our own transmission setup, decode and play them anyway 2022-12-21 13:28:28 +01:00
Thomas Göttgens
44a33ed463 add IO7 to RAK pinouts - only comments changed 2022-12-21 13:28:28 +01:00
Thomas Göttgens
fab08b6451 fix building for screenless devices 2022-12-21 13:28:28 +01:00
Thomas Göttgens
d9cd3dd3e1 Change Boot Message format 2022-12-21 13:28:25 +01:00
Thomas Göttgens
c75ea87f6b Format received message screen like sender in canned messages. 2022-12-21 13:28:25 +01:00
Thomas Göttgens
706ddf6e95 show appropriate message when going into OTA mode 2022-12-21 13:28:25 +01:00
Thomas Göttgens
aec091e7aa manual master merge
# Conflicts:
#	src/Power.cpp
2022-12-21 13:28:25 +01:00
Thomas Göttgens
cea8393a7f Merge pull request #2026 from GUVWAF/develop
TraceRouteModule
2022-12-21 13:27:12 +01:00
Thomas Göttgens
8f94463eac send a 4 byte magic header including the codec version 2022-12-21 13:27:00 +01:00
Thomas Göttgens
a0f5e44967 Audio Module is finished for regression tests. 2022-12-21 13:27:00 +01:00
Thomas Göttgens
feb7181767 debug print thread count. max_threads is 32 2022-12-21 13:27:00 +01:00
Thomas Göttgens
a0c1e9cdc6 Still WIP, but first working version of audio. I2S works good, analogue not so much. 2022-12-21 13:27:00 +01:00
Thomas Göttgens
7d1b6f63b5 Definition cleanup and AudioModule WIP 2022-12-21 13:27:00 +01:00
Thomas Göttgens
ab6b6514cb this define is arch specific 2022-12-21 13:26:59 +01:00
Thomas Göttgens
0e6285edf2 add temp code for heap debugging. Disable -DDEBUG_HEAP for release builds.
DEBUG_MSG output only for now.
2022-12-21 13:26:59 +01:00
Thomas Göttgens
8b58eaac20 fix compile
# Conflicts:
#	protobufs
2022-12-21 13:26:59 +01:00
Thomas Göttgens
8cbf292373 WIP: add digital audio. Needs a proto change, so checking in generated files for now.
# Conflicts:
#	src/mesh/generated/localonly.pb.h
#	src/mesh/generated/module_config.pb.h
2022-12-21 13:26:44 +01:00
Thomas Göttgens
80d0b63c3a hopefully fix compilation errors 2022-12-21 13:26:13 +01:00
Thomas Göttgens
f5120a29ec WIP: audio module still does not work, but enabled for all regions where audio is permitted.
# Conflicts:
#	variants/tlora_v2_1_18/platformio.ini
2022-12-21 13:26:13 +01:00
Thomas Göttgens
efc3f4c0ee remove a few DSR Router bits for S&F Module 2022-12-21 13:25:12 +01:00
Thomas Göttgens
bd2bfd6822 update board definition, update copy/paste errors, fix SX1280. 2022-12-21 13:25:12 +01:00
Thomas Göttgens
88c3ab2636 Merge pull request #2050 from lesykm/serial-module-simple-mode-fix
[modules][serial] fix simple module ability to send
2022-12-21 12:43:13 +01:00
Thomas Göttgens
6a5dd26907 need to trigger new CI run 2022-12-21 12:24:38 +01:00
Mykhailo Lesyk
4de557b4db [modules][serial] fix simple module ability to send 2022-12-21 01:35:19 -08:00
Thomas Göttgens
af9d4328eb Merge pull request #2046 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-12-17 18:42:25 +01:00
caveman99
8c66940b78 [create-pull-request] automated change 2022-12-17 17:41:39 +00:00
Thomas Göttgens
72f1416b30 add variant comment about radiolib 2022-12-16 20:21:56 +01:00
Thomas Göttgens
05f81922e6 Merge pull request #2040 from D4rk4/master
Disable deep sleep for nRF  and force shutdown for RAK463x on discharged battery
2022-12-15 11:21:26 +01:00
Dmitry Galenko
72504a5e8b Merge branch 'master' into master 2022-12-14 20:27:20 +01:00
Thomas Göttgens
e8c034e988 Merge pull request #2041 from markbirss/master
Fix power enable pin used for e-Ink
2022-12-14 17:39:13 +01:00
Dmitry Galenko
aa19718ba4 Change condition for low-voltage killswitch 2022-12-14 17:26:55 +01:00
Mark Trevor Birss
088ab106dd Update variant.h 2022-12-14 17:57:02 +02:00
Mark Trevor Birss
110c3f619a Update variant.h 2022-12-14 17:56:44 +02:00
Dmitry Galenko
d1cc503ca8 Disable shutdown for non ESP32 boards 2022-12-14 14:36:15 +01:00
Thomas Göttgens
d3b3a4c148 fix build error 2022-12-14 10:29:45 +01:00
Dmitry Galenko
46f1cee2a8 Fix missed braces and etc 2022-12-14 10:21:11 +01:00
Dmitry Galenko
0386af721d Merge branch 'meshtastic:master' into master 2022-12-14 09:45:35 +01:00
Thomas Göttgens
de6b752db8 Merge pull request #2039 from ghostop14/master
Enable GPS capabilities on heltec V3
2022-12-14 09:38:06 +01:00
Dmitry Galenko
92fd5511ec Disable nRF sleep on discharge 2022-12-14 09:36:25 +01:00
ghostop14
59ec7f31ab Enable GPS capabilities on heltec V3 2022-12-13 12:31:39 -05:00
Ben Meadors
779d2352bd Merge pull request #2037 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-12-12 16:29:39 -06:00
thebentern
0162db12b8 [create-pull-request] automated change 2022-12-12 19:23:34 +00:00
Ben Meadors
91ff7b9032 Merge pull request #2036 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-12-12 12:18:06 -06:00
thebentern
643f99f577 [create-pull-request] automated change 2022-12-12 18:06:11 +00:00
Ben Meadors
152288b4cc Merge pull request #2025 from meshtastic/power-fsm-experiment
Power FSM experiment
2022-12-12 12:01:00 -06:00
Ben Meadors
45b518baf2 Move sds transition back into esp32 only 2022-12-12 10:24:51 -06:00
Ben Meadors
0c65c73f90 Merge branch 'master' into power-fsm-experiment 2022-12-09 19:50:26 -06:00
Thomas Göttgens
0f0dbc3274 reboot nrf52 on critical error 8 2022-12-09 11:18:43 +01:00
Thomas Göttgens
06d34daeab Merge branch 'master' into power-fsm-experiment 2022-12-08 10:18:01 +01:00
Thomas Göttgens
ba1f68d758 Merge pull request #2027 from lewisxhe/master
Fix the charging parmas error of tbeam-s3core and change the default USB mode
2022-12-06 16:39:38 +01:00
Thomas Göttgens
d4c0977a70 Merge branch 'master' into master 2022-12-06 15:49:32 +01:00
Thomas Göttgens
1a19d71e95 Merge pull request #2023 from meshtastic/2022-bug-recording-critical-error-11-at-srcmeshradiolibinterfacecpp389
Add debug output
2022-12-06 15:48:57 +01:00
Thomas Göttgens
21c10934fc Merge pull request #2018 from arduionoGP/patch-3
Update MQTT.cpp
2022-12-06 15:47:30 +01:00
Thomas Göttgens
13cca91097 Merge branch 'master' into patch-3 2022-12-06 14:09:29 +01:00
Thomas Göttgens
b335b1c66b Merge branch 'master' into 2022-bug-recording-critical-error-11-at-srcmeshradiolibinterfacecpp389 2022-12-06 14:08:48 +01:00
Thomas Göttgens
cc2653bfb5 Merge pull request #2029 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-12-06 14:05:51 +01:00
caveman99
fc5bf5a68f [create-pull-request] automated change 2022-12-06 13:03:26 +00:00
lewishe
63d7338311 fix tbeams3-core PMU charging cut-off voltage 2022-12-06 11:01:14 +08:00
lewishe
37f716d27b Change tbeams3-core the default USB mode to TinyUSB 2022-12-06 10:58:59 +08:00
Ben Meadors
0f2a835359 Remove hard coded !isPowered 2022-12-05 10:13:19 -06:00
Thomas Göttgens
2a84d39e40 Always do battery resampling if we use the ADC. Improves reading a lot. 2022-12-05 16:40:23 +01:00
Ben Meadors
b14289e976 More cleanup 2022-12-05 08:35:54 -06:00
Ben Meadors
1fef6f0656 Clean up on battery shutdown condition 2022-12-05 07:37:01 -06:00
Thomas Göttgens
183ec2124f Add debug output 2022-12-05 11:48:46 +01:00
Ben Meadors
aeb9bfa063 Return false 2022-12-04 20:41:00 -06:00
arduinoGP
b84c7ae49b Oops, added time to the Pos 2022-12-04 19:41:58 -05:00
Thomas Göttgens
61598c5942 Merge pull request #2020 from meshtastic/serial-textmessage
Serial textmessage mode
2022-12-04 23:53:29 +01:00
Ben Meadors
a3a24e0216 Don't put newlines in the text buffer 2022-12-04 16:03:57 -06:00
Ben Meadors
31ec2da0e9 Text message mode for serial 2022-12-04 15:40:28 -06:00
arduinoGP
27a10b395f Update MQTT.cpp
(First real try at writing meaningful C++ but it seems to work.)
Allows sending JSON Position data from MQTT broker for broadcast to a LORA mesh via gateway device.
The new type is "sendposition". Valid envelope looks like:
{
    "sender": "someSender",
    "type": "sendposition",
    "payload": {
        "latitude_i": 399600000,
        "longitude_i": -862600000,
        "altitude": 100
    }
}
This complements the "sendtext" type envelope.
2022-12-04 00:00:43 -05:00
Ben Meadors
7570cdbd22 Fix shell scripts for both linux and darwin 2022-12-03 08:24:11 -06:00
Thomas Göttgens
c857474116 Merge pull request #2013 from arduionoGP/patch-2
Update MQTT.cpp
2022-12-01 22:17:35 +01:00
arduinoGP
8ff5dacc3c Update MQTT.cpp
case Portnum_POSITION_APP adjusted so the various options allways get encoded into JSON as long as lat and long are present. There are circumstances where timestamp, time, or altitude might be missing and this causes silent failures of JSON encoding..
2022-12-01 15:44:47 -05:00
Ben Meadors
f1179d31ba Fixed shell scripts 2022-11-27 07:40:40 -06:00
Ben Meadors
abe60b96f1 Merge pull request #2001 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-11-27 06:11:39 -06:00
thebentern
206520f179 [create-pull-request] automated change 2022-11-27 02:16:21 +00:00
Ben Meadors
97fd5cf2ab Merge pull request #2000 from meshtastic/develop
Develop upstream
2022-11-26 19:16:24 -06:00
Ben Meadors
d13a095516 Merge pull request #1990 from GUVWAF/develop
Send 'ACK' response for handled admin message
2022-11-26 19:15:36 -06:00
Ben Meadors
4dc7d92cf1 Merge pull request #1999 from meshtastic/master
Fix conditional syntax
2022-11-26 15:09:56 -06:00
Ben Meadors
e7dbbeb606 Fix conditional syntax 2022-11-26 14:50:07 -06:00
GUVWAF
3e892fc391 Merge branch 'meshtastic:develop' into develop 2022-11-26 21:14:52 +01:00
Ben Meadors
dfec37dfd0 Merge pull request #1996 from meshtastic/master
Develop downstream
2022-11-26 12:59:54 -06:00
Ben Meadors
b82ab34f85 Merge pull request #1993 from meshtastic/potential-sx1262-fix
Don't set DIO2 switch if TXEN is defined
2022-11-26 12:59:02 -06:00
Ben Meadors
18a2cfeda4 Merge branch 'master' into potential-sx1262-fix 2022-11-26 10:18:14 -06:00
Thomas Göttgens
082aa07e7f update batch scripts to further check filename. 2022-11-26 17:00:33 +01:00
Ben Meadors
a703ab4418 Merge branch 'master' into potential-sx1262-fix 2022-11-26 09:07:59 -06:00
Thomas Göttgens
185ceac9df Merge pull request #1994 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-11-26 16:06:12 +01:00
caveman99
7c9cada50e [create-pull-request] automated change 2022-11-26 15:04:12 +00:00
Thomas Göttgens
a5ba3dd445 revert protobuf change to develop 2022-11-26 16:03:17 +01:00
Ben Meadors
63838a1632 Merge branch 'master' into potential-sx1262-fix 2022-11-26 08:19:13 -06:00
Ben Meadors
30d7f188e2 Merge pull request #1991 from meshtastic/develop
Merge develop to master
2022-11-26 08:18:59 -06:00
Ben Meadors
47a47f1e69 Merge branch 'master' into develop 2022-11-26 08:18:35 -06:00
Ben Meadors
daac79f314 Merge branch 'master' into potential-sx1262-fix 2022-11-26 08:13:05 -06:00
Ben Meadors
1864216e78 Merge pull request #1992 from lewisxhe/master
Fix the format of t-echo Bluetooth pairing display page
2022-11-26 08:12:55 -06:00
Ben Meadors
71c0cf9b9a Don't set DIO2 switch if TXEN is defined 2022-11-26 08:11:32 -06:00
Ben Meadors
ef87ddb798 Merge branch 'master' into master 2022-11-26 07:44:19 -06:00
Ben Meadors
711c748b44 Merge pull request #1986 from IhorNehrutsa/MESSAGES
Some DEBUG_MSG added/changed/commented.
2022-11-26 07:44:12 -06:00
lewis
6eff09a260 Merge branch 'master' of https://github.com/meshtastic/Meshtastic-device 2022-11-26 21:38:07 +08:00
lewis
c5fe878a6f Fix the format of t-echo Bluetooth pairing display page 2022-11-26 21:37:32 +08:00
Thomas Göttgens
39948c76de Merge branch 'master' into develop 2022-11-26 14:19:27 +01:00
Ben Meadors
10f14d27b7 Merge branch 'master' into MESSAGES 2022-11-26 07:13:20 -06:00
Ben Meadors
5e9d722b7d Merge pull request #1987 from lewisxhe/master
Add t-echo to the operation after the flash operation fails
2022-11-26 06:59:03 -06:00
Ben Meadors
b324c04097 Merge branch 'master' into master 2022-11-26 06:44:28 -06:00
Ben Meadors
84a9d95b1f Merge branch 'master' into MESSAGES 2022-11-26 06:43:52 -06:00
lewis
cdd499f147 Add missing restart parameters 2022-11-26 12:10:10 +08:00
GUVWAF
c45a85547e Send 'ACK' response for admin message 2022-11-25 20:33:24 +01:00
GUVWAF
8815746006 Fix wrong comment 2022-11-25 20:33:23 +01:00
Garth Vander Houwen
32a1e8ef0d Create feature.yml 2022-11-25 09:44:26 -08:00
lewis
0dff4538f3 Add t-echo to the operation after the flash operation fails 2022-11-26 00:17:54 +08:00
Ihor Nehrutsa
6507683909 Squashed commit of the following:
commit c8d1bcf04fae5f7ac5b639ddd15a738045014c95
Author: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
Date:   Fri Nov 25 15:11:18 2022 +0200

    Revert "variants\tbeam\variant.h: Use LORA_CS instead of RF95_NSS"

    This reverts commit 8d225ced9c.

commit 1c37097448393ea9364c2b9bf10522802c61d5c4
Author: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
Date:   Fri Nov 25 15:04:09 2022 +0200

    Some little debugs added

commit f1b55e11af
Author: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
Date:   Wed Nov 23 15:24:58 2022 +0200

    Update variant.h

commit 8d225ced9c
Author: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
Date:   Wed Nov 23 13:06:49 2022 +0200

    variants\tbeam\variant.h: Use LORA_CS instead of RF95_NSS
2022-11-25 15:17:24 +02:00
Ben Meadors
c71e32970c Merge pull request #1982 from meshtastic/master
Master to Develop
2022-11-24 08:07:24 -06:00
Thomas Göttgens
fcf21da843 one radiolib to rule them all 2022-11-24 13:55:57 +01:00
Thomas Göttgens
ab464fe038 compress better 2022-11-24 13:07:37 +01:00
Thomas Göttgens
fd546af2a5 don't package meshtasticd simulator
that saves 5 MB on every zip.
2022-11-24 12:36:47 +01:00
Thomas Göttgens
acfbe202b6 include alternative update bin without bootloader and settings 2022-11-24 12:33:19 +01:00
Thomas Göttgens
29fb283daf adaptig for #1938 2022-11-24 12:30:15 +01:00
Thomas Göttgens
51ef9b7fbe fix RP2040 and Portduino Platforms 2022-11-24 12:24:57 +01:00
Thomas Göttgens
025d2264a2 m5stack runs with native tone support now. 2022-11-24 10:44:43 +01:00
Thomas Göttgens
b2284b2097 Tone now included in arduino core for ESP32. 2022-11-24 10:30:11 +01:00
Thomas Göttgens
5f8267c956 use the buzzer for external notification module 2022-11-24 10:11:42 +01:00
Thomas Göttgens
cf783a5bae make GPS pins configurable through protos 2022-11-24 09:23:17 +01:00
Thomas Göttgens
32e5ced814 regen protos 2022-11-24 09:22:50 +01:00
Thomas Göttgens
605fadabcf Merge branch 'master' of github.com:meshtastic/firmware 2022-11-24 00:03:45 +01:00
Thomas Göttgens
e91ace7329 Merge pull request #1980 from meshtastic/master
Master Merge again
2022-11-24 00:02:35 +01:00
Thomas Göttgens
c87cd136d4 Merge pull request #1979 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-11-24 00:01:39 +01:00
Thomas Göttgens
0d7d59609a Remove gpio binding for notification module. 2022-11-23 23:49:29 +01:00
thebentern
75ed0e5906 [create-pull-request] automated change 2022-11-23 22:49:22 +00:00
Thomas Göttgens
8e3b500307 ---EXPERIMENTAL--- reboot the board if the NO_AP_FOUND error comes back. 2022-11-23 23:47:50 +01:00
Thomas Göttgens
d6f77bf07e Merge pull request #1978 from meshtastic/master
Master to Develop
2022-11-23 23:44:42 +01:00
Ben Meadors
65e8209d51 Merge pull request #1976 from markbirss/master
M5Stack CoreInk enable buzzer
2022-11-23 14:32:18 -06:00
Ben Meadors
aae5247caa Merge pull request #1977 from meshtastic/hotfix-reset-nodedb
Hotfix Add reset nodedb handler back
2022-11-23 14:31:50 -06:00
Ben Meadors
2fedb6b774 Add reset nodedb handler back 2022-11-23 14:12:44 -06:00
Mark Trevor Birss
02d18d4831 Merge branch 'master' into master 2022-11-23 21:53:12 +02:00
Ben Meadors
b70c2d088d Merge pull request #1975 from GUVWAF/master
Revert "Override RoutingModule's ACK if on wrong channel"
2022-11-23 13:50:42 -06:00
Mark Trevor Birss
b3c396683e Update platformio.ini 2022-11-23 21:25:19 +02:00
Mark Trevor Birss
f08874dd37 Update platformio.ini 2022-11-23 21:24:34 +02:00
Mark Trevor Birss
648054da9b Add files via upload 2022-11-23 21:19:20 +02:00
GUVWAF
70bf7c490c Revert "Override RoutingModule's ACK if on wrong channel"
This reverts commit 71c163a8ee.
2022-11-23 19:27:57 +01:00
Thomas Göttgens
adbed5de95 - fix NTP sync on connect
- disable extended GPS mode again
- add --inline-suppr to cppflags
2022-11-22 17:19:24 +01:00
Thomas Göttgens
fe989f0bff Merge pull request #1973 from meshtastic/master
Develop refresh to Master
2022-11-22 17:08:04 +01:00
Thomas Göttgens
679e346bcb change old field denominator 2022-11-22 16:47:54 +01:00
Thomas Göttgens
832439b336 strange enough _that_ suppression works 2022-11-22 15:56:13 +01:00
Thomas Göttgens
71c2af04ec why is this working on pio/windows? 2022-11-22 15:03:01 +01:00
Ben Meadors
0f4261d02f Merge pull request #1972 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-11-22 07:40:41 -06:00
Thomas Göttgens
23466d8eee yank that dreaded json11 - first try 2022-11-22 14:29:00 +01:00
thebentern
8edbba2180 [create-pull-request] automated change 2022-11-22 00:56:46 +00:00
Ben Meadors
5417671332 Merge pull request #1971 from GUVWAF/master
Cover two ACK/NAK edge cases for admin packets
2022-11-21 18:11:25 -06:00
Ben Meadors
35d7e11678 Merge branch 'master' into master 2022-11-21 16:36:11 -06:00
Ben Meadors
7a63ba827b Merge pull request #1965 from meshtastic/transactional-config-edits
Only save and reboot while a transaction isnt open
2022-11-21 16:12:55 -06:00
GUVWAF
71c163a8ee Override RoutingModule's ACK if on wrong channel 2022-11-21 20:43:17 +01:00
GUVWAF
5d8e661807 Send NAK on primary channel if it cannot decode it 2022-11-21 20:43:17 +01:00
Ben Meadors
24244e8474 Update AdminModule.cpp 2022-11-21 12:24:05 -06:00
Ben Meadors
fb4f9bdc40 Merge branch 'master' into transactional-config-edits 2022-11-21 12:10:49 -06:00
Ben Meadors
668c46e0cf Merge pull request #1968 from meshtastic/develop
Merge develop upstream
2022-11-21 12:10:14 -06:00
Ben Meadors
abf8fdb661 Merge branch 'master' into develop 2022-11-21 09:39:22 -06:00
Ben Meadors
a28a04b7a0 Merge pull request #1964 from meshtastic/mqtt-init-defaults
Init default mqtt configurations
2022-11-21 09:39:10 -06:00
Ben Meadors
cd9671650b Merge branch 'master' into mqtt-init-defaults 2022-11-21 09:39:05 -06:00
Ben Meadors
00bc762bf1 Merge branch 'master' into develop 2022-11-21 09:38:46 -06:00
Thomas Göttgens
9a065bce03 Merge pull request #1970 from meshtastic/caveman99-OLED-FIX
fix TLora V1 Boards Display Init
2022-11-21 16:37:55 +01:00
Thomas Göttgens
3b2b0bdc97 fix TLora V1 Boards Display Init 2022-11-21 15:50:47 +01:00
Ben Meadors
53cd6bdf15 Merge branch 'master' into develop 2022-11-21 07:35:46 -06:00
Thomas Göttgens
edc97c1c07 Merge branch 'master' of github.com:meshtastic/firmware 2022-11-21 14:28:45 +01:00
Ben Meadors
6a24ef2263 Merge branch 'master' into transactional-config-edits 2022-11-21 07:26:18 -06:00
Ben Meadors
50ba523fb4 Merge branch 'master' into mqtt-init-defaults 2022-11-21 07:14:47 -06:00
Thomas Göttgens
a33325f90f update web server reference to latest commit 2022-11-21 13:46:22 +01:00
Thomas Göttgens
a173b7159a Merge pull request #1967 from D4rk4/SAST
Remove empty workflow file
2022-11-21 09:01:16 +01:00
Thomas Göttgens
91295d3772 Merge branch 'master' of github.com:meshtastic/firmware 2022-11-21 08:50:53 +01:00
Dmitry Galenko
9c1c04a8db Merge branch 'master' into SAST 2022-11-21 08:14:39 +01:00
Dmitry Galenko
51d0d0d779 Fix empty workflow 2022-11-21 08:13:28 +01:00
Dmitry Galenko
9cdf627ae3 Revert "Fix empty workflow"
This reverts commit 4b9c482384.
2022-11-21 08:12:52 +01:00
Dmitry Galenko
4b9c482384 Fix empty workflow 2022-11-21 08:10:21 +01:00
Ben Meadors
b1ba807ec9 Only save and reboot while a transaction isnt open 2022-11-20 19:50:45 -06:00
Ben Meadors
c844f153e1 Merge branch 'master' into mqtt-init-defaults 2022-11-20 15:31:54 -06:00
Thomas Göttgens
4a2b02347f Keymatrix Bugfix: Allow key 3 to send associated text
Feature: setting a text "~" emulates IO5/Userbutton with keymatrix.
2022-11-20 20:59:48 +01:00
Thomas Göttgens
e8a05d1874 Merge pull request #1947 from meshtastic/bug-1821
testing issues with RAK11200/13300
2022-11-20 19:40:52 +01:00
Ben Meadors
08c4e3fbd6 Merge branch 'master' into mqtt-init-defaults 2022-11-20 12:29:47 -06:00
Ben Meadors
1c5292ac86 Init default mqtt configurations 2022-11-20 12:29:10 -06:00
Ben Meadors
aa553ea5d8 Merge pull request #1958 from D4rk4/SAST
Implement automatic static code scan with Semgrep & Flawfinder
2022-11-20 11:10:19 -06:00
Thomas Göttgens
a00bd59e27 Merge branch 'master' of github.com:meshtastic/firmware 2022-11-20 18:03:18 +01:00
Thomas Göttgens
f02c6c49ee Merge branch 'master' into bug-1821 2022-11-20 17:26:42 +01:00
Dmitry Galenko
e54e37a600 Rename security workflows to sec_* 2022-11-20 16:17:58 +01:00
Dmitry Galenko
b95103cab0 Run flawfinder only on push to specific branch 2022-11-20 16:16:04 +01:00
Dmitry Galenko
9b43e49116 Ignore upstream defect 2022-11-20 16:14:32 +01:00
Ben Meadors
457538c8f6 Merge branch 'master' into SAST 2022-11-20 08:13:47 -06:00
Ben Meadors
da48f0704b Merge pull request #1960 from D4rk4/SEC
Security fixes
2022-11-20 08:05:04 -06:00
Dmitry Galenko
cf8d953bba Merge branch 'master' into SAST 2022-11-20 14:41:51 +01:00
Dmitry Galenko
5f2b859e38 Merge branch 'master' into SEC 2022-11-20 14:37:46 +01:00
Dmitry Galenko
3187b5abda Revert "Missed STDC_LIB_EXT1"
This reverts commit 4392df0676.
2022-11-20 14:29:05 +01:00
Ben Meadors
ce16b50d5f Change docker push critera 2022-11-20 07:05:49 -06:00
Dmitry Galenko
4295720770 Add flawfinder for cover C++ codebase 2022-11-20 13:50:38 +01:00
Dmitry Galenko
4392df0676 Missed STDC_LIB_EXT1 2022-11-20 13:27:55 +01:00
Dmitry Galenko
4ec3b025f0 look like https://sg.run/jkdn not hit us 2022-11-20 13:19:47 +01:00
Dmitry Galenko
f4704181e9 Fix potential buffer clean issue 2022-11-20 13:12:51 +01:00
Dmitry Galenko
0e04bea39e Fix for Dockerfile-related security defects and rewrite to follow best practices 2022-11-20 12:57:55 +01:00
Thomas Göttgens
b54044fd00 if we have a filename, 'address' is the line number. Don't print that in hex ;-)
If it's really a hex address, prefix it with 0x
2022-11-20 12:00:57 +01:00
Dmitry Galenko
08c69c09c8 Fix branch name 2022-11-20 11:58:15 +01:00
Dmitry Galenko
681ea420c1 Implement automatic static code scan with Semgrep 2022-11-20 10:53:11 +01:00
Sacha Weatherstone
48ea54748f Fix build instructions link 2022-11-20 06:38:17 +00:00
Ben Meadors
4b7627595a Merge branch 'master' into bug-1821 2022-11-19 20:05:03 -06:00
Ben Meadors
6299e5483b Input boards 2022-11-19 19:39:39 -06:00
Ben Meadors
6118a966a6 Move em up 2022-11-19 19:30:19 -06:00
Ben Meadors
1fac9ee1f2 More reusable workflows 2022-11-19 19:23:35 -06:00
Ben Meadors
1e06b2d51e I think understand now 2022-11-19 18:57:06 -06:00
Ben Meadors
f3a6ed9d61 Rename to action 2022-11-19 18:53:42 -06:00
Ben Meadors
f71cbb6f6e Move to actions folder 2022-11-19 18:50:50 -06:00
Ben Meadors
23ea22c741 Checkout master first 2022-11-19 18:42:27 -06:00
Ben Meadors
8be65bb0ab Move the checkout 2022-11-19 18:40:17 -06:00
Ben Meadors
57e2e75d24 Add shells 2022-11-19 18:35:00 -06:00
Ben Meadors
29cd7568f5 Try a composite action instead 2022-11-19 18:30:43 -06:00
Ben Meadors
581076a5a1 Now let's take it further 2022-11-19 18:07:07 -06:00
Ben Meadors
27401bb9b8 Remove runs-on 2022-11-19 17:48:01 -06:00
Ben Meadors
10837ce549 With block 2022-11-19 17:45:33 -06:00
Ben Meadors
1dcd411d00 Fix indention 2022-11-19 17:43:18 -06:00
Ben Meadors
0533fd9227 Uses 2022-11-19 17:35:47 -06:00
Ben Meadors
5ce7ffc888 Show contents 2022-11-19 16:51:33 -06:00
Ben Meadors
9e914de995 Try going up a dir 2022-11-19 16:46:36 -06:00
Ben Meadors
0cc653263e Indent 2022-11-19 16:39:05 -06:00
Ben Meadors
d2d2f278cf Apparently checkout before using a local workflow 2022-11-19 16:25:00 -06:00
Ben Meadors
eb34a95ab7 Why fight me? 2022-11-19 16:23:09 -06:00
Ben Meadors
eb1f6c0de6 Root path? 2022-11-19 16:13:26 -06:00
Ben Meadors
8de79e8fb6 Path 2022-11-19 16:08:11 -06:00
Ben Meadors
fe00f0c369 Uses block 2022-11-19 16:06:59 -06:00
Ben Meadors
f9ee8583b0 Merge pull request #1956 from meshtastic/docker-hub-and-ci-overhaul
Docker hub and ci overhaul
2022-11-19 16:04:21 -06:00
Ben Meadors
a4d5f8c717 Reusable workflow 2022-11-19 16:03:55 -06:00
Ben Meadors
35c50f074b Build and push to docker hub 2022-11-19 15:44:59 -06:00
Ben Meadors
dcfa226509 Remove extra git submodule update 2022-11-19 15:42:08 -06:00
Thomas Göttgens
a9fde30a58 Merge branch 'master' into bug-1821 2022-11-19 10:00:41 +01:00
Thomas Göttgens
7ceb52103e Cleaning up GPS Code a bit 2022-11-19 09:58:29 +01:00
Thomas Göttgens
8da5d37888 Merge branch 'master' of github.com:meshtastic/firmware 2022-11-19 09:56:11 +01:00
Thomas Göttgens
95cc328b5c That wifi update didn't go down well. 2022-11-18 19:37:56 +01:00
Thomas Göttgens
990c0119a7 fix portduino - again 2022-11-18 18:22:35 +01:00
Thomas Göttgens
144afee29e trigger wifi reconnect by mqtt or ntp failures. 2022-11-18 18:03:30 +01:00
Thomas Göttgens
9665c08b59 MQTT: don't subscribe to JSON topic if JSON is disabled in config. 2022-11-17 21:14:49 +01:00
Ben Meadors
20ee6a509d Remove more targets from checks 2022-11-17 13:35:16 -06:00
Thomas Göttgens
70d44b8838 next try. 2022-11-17 20:19:11 +01:00
Thomas Göttgens
b260c8b058 tryfix wifi issues 2022-11-17 20:09:08 +01:00
Thomas Göttgens
5991b59ba3 try fixing Wifi reconnects - don't manually reconnect and set auto-reconnect at the same time. 2022-11-17 17:48:46 +01:00
Ben Meadors
bc1fed0fb4 Merge branch 'bug-1821' of https://github.com/meshtastic/firmware into bug-1821 2022-11-15 16:23:08 -06:00
Ben Meadors
b23c364fc0 Test it this way 2022-11-15 16:22:53 -06:00
Thomas Göttgens
28b428c5a0 potential fix for 13300 2022-11-15 22:54:31 +01:00
Thomas Göttgens
5bfc58ed64 testing issues with RAK11200/13300 2022-11-15 21:55:27 +01:00
Thomas Göttgens
e9a34fca7b Portduino Radiolib upstream 2022-11-15 17:01:15 +01:00
Thomas Göttgens
6ce9734ddd Merge pull request #1944 from meshtastic/master
Master Merge
2022-11-15 11:06:14 +01:00
Thomas Göttgens
d42797ffeb fix Portduino Step 1 2022-11-15 10:49:55 +01:00
Thomas Göttgens
b5ebfa9cc3 Portduino WIP 2022-11-15 07:59:01 +01:00
Thomas Göttgens
79eff42c3c Fix and Break radiolib 2022-11-14 10:53:16 +01:00
Thomas Göttgens
7022807fa3 Merge pull request #1943 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-11-14 10:01:13 +01:00
Thomas Göttgens
50a301899e start to sort radiolib out. If we have macros, use them! :-)
Also we need Godmode for the SX1280 for now, hopefully can revert to more sane operation.
2022-11-14 09:49:50 +01:00
thebentern
351db5f6ef [create-pull-request] automated change 2022-11-14 08:40:21 +00:00
Ben Meadors
09fe616ac5 This number is a joke 2022-11-13 18:16:40 -06:00
Ben Meadors
2d7ff39ecc Merge pull request #1942 from meshtastic/develop
Develop to Master
2022-11-13 15:42:41 -06:00
Ben Meadors
6e856efd0e Merge branch 'master' into develop 2022-11-13 14:45:48 -06:00
Ben Meadors
c3c899bc85 Upstream protos for resolving conflicts 2022-11-13 14:45:26 -06:00
Ben Meadors
916f3cac41 Sync protos 2022-11-13 14:40:18 -06:00
Ben Meadors
9b5f358823 Add new heltec targets 2022-11-13 14:30:32 -06:00
Ben Meadors
22119c272d Merge pull request #1941 from meshtastic/add-heltec-wsl
Add Heltec Wireless Stick Lite V3 support
2022-11-13 14:09:50 -06:00
Ben Meadors
8d4c526d16 Add Heltec Wireless Stick Lite V3 support 2022-11-13 13:28:02 -06:00
Ben Meadors
83aebb7a00 Merge pull request #1940 from meshtastic/add-heltec-v3
Added support for Heltec V3
2022-11-13 10:31:37 -06:00
Ben Meadors
33cd5ce6c1 Cleanup 2022-11-13 09:48:38 -06:00
Ben Meadors
f22c2e768e Reorder 2022-11-13 09:47:55 -06:00
Ben Meadors
3d7dea0606 Added support for Heltec V3 2022-11-13 09:45:16 -06:00
Thomas Göttgens
263a421c4a fix pico build 2022-11-13 15:35:18 +01:00
Thomas Göttgens
401b92bdbb reverted too much 2022-11-13 15:28:43 +01:00
Thomas Göttgens
6a696af8f6 Revert "remember which devices were scanned on which bus and set them accordingly." - this is not working at all. 2022-11-13 14:56:52 +01:00
Thomas Göttgens
037d6c253b fix portduino 2022-11-13 11:58:02 +01:00
Thomas Göttgens
b6de79b21a fix build for RP2040 which actually has 2 TwoWire interfaces. 2022-11-12 17:50:33 +01:00
Thomas Göttgens
52cf530356 missing 2 sensor changes 2022-11-12 17:18:17 +01:00
Thomas Göttgens
861ded37db remember which devices were scanned on which bus and set them accordingly. 2022-11-12 17:12:40 +01:00
Thomas Göttgens
7a67388a97 Merge branch 'master' of github.com:meshtastic/firmware into develop 2022-11-12 14:34:51 +01:00
Thomas Göttgens
4f60fad3f6 Merge pull request #1936 from lewisxhe/master
Update tbeam-s3 variant
2022-11-12 14:12:11 +01:00
lewis he
67efd8172a Merge branch 'master' into master 2022-11-12 20:11:52 +08:00
lewis
60fdf9fcb2 Place PMU initialization before scanI2Cdevice 2022-11-12 20:09:25 +08:00
Thomas Göttgens
a606e9b7b5 Merge pull request #1935 from puzzled-pancake/patch-1
Update NZ_865 to 36dBm
2022-11-12 11:55:37 +01:00
Thomas Göttgens
65197a8e48 - Add new Compass Sensor
- speed up I2C Scanning
- make adding sensors less error prone
2022-11-12 11:03:29 +01:00
lewishe
43f769ebac Resolve compilation conflicts 2022-11-12 16:01:30 +08:00
lewishe
dff6eeb90e Merge branch 'master' of https://github.com/lewisxhe/Meshtastic-device 2022-11-12 15:16:54 +08:00
lewishe
61ebdb3367 Add SD card initialization 2022-11-12 15:14:13 +08:00
lewishe
cd95d0865f Repair the sharing of Wire1 between RTC and PMU in tbeams3 2022-11-12 15:12:53 +08:00
lewishe
b68a026627 Update tbeam-s3 variant mapping 2022-11-12 14:39:42 +08:00
lewishe
68ccebafbf Add low-speed crystal initialization for ESP32S3 2022-11-12 14:38:48 +08:00
puzzled-pancake
3737252d39 Update NZ_865 to 36dBm
Updated NZ_865 to 36dBm as per:
https://rrf.rsm.govt.nz/smart-web/smart/page/-smart/domain/licence/LicenceSummary.wdk?id=219752

6dBW = 36dBm/4watt
2022-11-12 17:55:28 +13:00
lewis he
888a8d05c4 Merge branch 'meshtastic:master' into master 2022-11-12 09:56:18 +08:00
Thomas Göttgens
f25f902c20 max power for the 1280 is +13dBm 2022-11-11 08:59:16 +01:00
Thomas Göttgens
a6ea5496b4 Fixed DIO Pin mapping. SX1280 is working 2022-11-10 23:26:31 +01:00
Thomas Göttgens
222424a80c no excuses, this was a SNAFU 2022-11-10 23:06:37 +01:00
Thomas Göttgens
74f31d7d68 Fix SX1280 init 2022-11-10 23:00:01 +01:00
Thomas Göttgens
5c59c8d701 GPS Update 2022-11-10 22:21:07 +01:00
Ben Meadors
30a87e3145 Switch to a smaller sample of devices for cppcheck 2022-11-10 07:26:28 -06:00
Thomas Göttgens
87f7a60f71 fix #1931 coordinates inserted into NMES stream 2022-11-10 13:51:22 +01:00
Thomas Göttgens
f7d8885257 update coordinates for DMS display too 2022-11-10 13:50:38 +01:00
Thomas Göttgens
77410dc3c3 Merge pull request #1932 from meshtastic/master
Master Merge
2022-11-10 11:02:38 +01:00
Thomas Göttgens
d1acf02ee8 Master Merge 2022-11-10 11:01:36 +01:00
Thomas Göttgens
de0954f307 switch to upstream Ethernet lib 2022-11-10 09:35:56 +01:00
Ben Meadors
7da1e5c3e8 Merge pull request #1930 from meshtastic/bug-1928
fix #1928 valid NMEA sentences
2022-11-09 18:06:01 -06:00
Thomas Göttgens
3c11e87197 Merge pull request #1927 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2022-11-09 23:43:35 +01:00
Thomas Göttgens
b004706eff fix #1928 valid NMEA sentences 2022-11-09 23:42:52 +01:00
thebentern
2247e71a52 [create-pull-request] automated change 2022-11-09 21:39:27 +00:00
Thomas Göttgens
30b6cca366 Merge pull request #1925 from meshtastic/bug-1914
fix #1914 and clean up rangetest a bit
2022-11-09 15:14:47 +01:00
Thomas Göttgens
4dd140a887 fix #1914 and clean up rangetest a bit 2022-11-09 15:12:57 +01:00
Ben Meadors
87c555bde3 Changed retention policy 2022-11-09 14:48:53 +01:00
Ben Meadors
c4951b1236 Build cleanup and update deprecated platformio cmd 2022-11-09 14:48:53 +01:00
thebentern
0249eb1307 [create-pull-request] automated change 2022-11-09 14:48:53 +01:00
Thomas Göttgens
803858ab0a change default pins for codec2 to work on TLORA 2.1-1.8 2022-11-09 11:50:13 +01:00
lewis he
da2279c295 Merge branch 'meshtastic:master' into master 2022-10-22 18:22:12 +08:00
lewishe
13e635b74e Add judgment on t-beam-s3-core to scanI2Cdevice in main.cpp 2022-10-10 11:50:18 +08:00
140 changed files with 3800 additions and 1556 deletions

27
.github/ISSUE_TEMPLATE/feature.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Feature Request
description: Request a new feature
title: "[Feature Request]: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for your request this will not gurantee that we will implement it, but it will be reviewed.
- type: dropdown
id: soc
attributes:
label: Platform
description: What device platform will support your feature?
multiple: true
options:
- NRF52
- ESP32
validations:
required: true
- type: textarea
id: body
attributes:
label: Description
description: Please provide details about your enhancement.
validations:
required: true

41
.github/actions/setup-base/action.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: 'Setup Build Base Composite Action'
description: 'Base build actions for Meshtastic Platform IO steps'
runs:
using: "composite"
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: "recursive"
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install cppcheck
shell: bash
run: |
sudo apt-get install -y cppcheck
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools
shell: bash
run: |
python -m pip install --upgrade pip
pip install -U platformio adafruit-nrfutil
pip install -U meshtastic --pre
- name: Upgrade platformio
shell: bash
run: |
pio upgrade

54
.github/workflows/build_esp32.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: Build ESP32
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-esp32:
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@master
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: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "meshtastic/firmware-ota"
file: "firmware.bin"
target: "release/bleota.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

33
.github/workflows/build_nrf52.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Build NRF52
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-nrf52:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build NRF52
run: bin/build-nrf52.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.uf2
release/*.elf
release/*.zip

32
.github/workflows/build_rpi2040.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Build RPI2040
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-rpi2040:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build Raspberry Pi 2040
run: ./bin/build-rpi2040.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.uf2
release/*.elf

View File

@@ -23,61 +23,22 @@ jobs:
matrix: matrix:
include: include:
- board: rak11200 - board: rak11200
- board: tlora-v2
- board: tlora-v1
- board: tlora_v1_3
- board: tlora-v2-1-1.6 - board: tlora-v2-1-1.6
- board: tbeam - board: tbeam
- board: heltec-v1
- board: heltec-v2.0
- board: heltec-v2.1 - board: heltec-v2.1
- board: tbeam0.7
- board: meshtastic-diy-v1 - board: meshtastic-diy-v1
- board: meshtastic-dr-dev
- board: rak4631 - board: rak4631
- board: rak4631_eink
- board: t-echo - board: t-echo
- board: nano-g1
- board: station-g1 - board: station-g1
- board: m5stack-core
- board: m5stack-coreink - board: m5stack-coreink
- board: tbeam-s3-core - board: tbeam-s3-core
- board: feather_diy
# - board: pico
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - uses: actions/checkout@v3
uses: actions/checkout@v3 - name: Build base
with: id: base
submodules: "recursive" uses: ./.github/actions/setup-base
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install cppcheck
run: |
sudo apt-get install -y cppcheck
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools and install platformio
run: |
python -m pip install --upgrade pip
pip install -U platformio
- name: Upgrade platformio
run: |
pio upgrade
- name: Check ${{ matrix.board }} - name: Check ${{ matrix.board }}
run: bin/check-all.sh ${{ matrix.board }} run: bin/check-all.sh ${{ matrix.board }}
@@ -96,6 +57,8 @@ jobs:
- board: heltec-v1 - board: heltec-v1
- board: heltec-v2.0 - board: heltec-v2.0
- board: heltec-v2.1 - board: heltec-v2.1
- board: heltec-v3
- board: heltec-wsl-v3
- board: tbeam0.7 - board: tbeam0.7
- board: meshtastic-diy-v1 - board: meshtastic-diy-v1
- board: meshtastic-dr-dev - board: meshtastic-dr-dev
@@ -104,73 +67,9 @@ jobs:
- board: m5stack-core - board: m5stack-core
- board: m5stack-coreink - board: m5stack-coreink
- board: tbeam-s3-core - board: tbeam-s3-core
uses: ./.github/workflows/build_esp32.yml
runs-on: ubuntu-latest with:
steps: board: ${{ matrix.board }}
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: "recursive"
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools
run: |
python -m pip install --upgrade pip
pip install -U platformio adafruit-nrfutil
- name: Upgrade platformio
run: |
pio upgrade
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
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: Build ESP32
run: bin/build-esp32.sh ${{ matrix.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "meshtastic/firmware-ota"
file: "firmware.bin"
target: "release/bleota.bin"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.bin
release/*.elf
retention-days: 30
build-nrf52: build-nrf52:
strategy: strategy:
@@ -183,53 +82,9 @@ jobs:
- board: t-echo - board: t-echo
- board: pca10059_diy_eink - board: pca10059_diy_eink
- board: feather_diy - board: feather_diy
uses: ./.github/workflows/build_nrf52.yml
runs-on: ubuntu-latest with:
steps: board: ${{ matrix.board }}
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: "recursive"
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools
run: |
python -m pip install --upgrade pip
pip install -U platformio adafruit-nrfutil
- name: Upgrade platformio
run: |
pio upgrade
- name: Build NRF52
run: bin/build-nrf52.sh ${{ matrix.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.uf2
release/*.elf
release/*.zip
retention-days: 30
build-rpi2040: build-rpi2040:
strategy: strategy:
@@ -238,84 +93,17 @@ jobs:
matrix: matrix:
include: include:
- board: pico - board: pico
uses: ./.github/workflows/build_rpi2040.yml
runs-on: ubuntu-latest with:
steps: board: ${{ matrix.board }}
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: "recursive"
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools
run: |
python -m pip install --upgrade pip
pip install -U platformio adafruit-nrfutil
- name: Upgrade platformio
run: |
pio upgrade
- name: Build Raspberry Pi 2040
run: ./bin/build-rpi2040.sh ${{ matrix.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.uf2
release/*.elf
retention-days: 30
build-native: build-native:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - uses: actions/checkout@v3
uses: actions/checkout@v3 - name: Build base
with: id: base
submodules: "recursive" uses: ./.github/actions/setup-base
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools
run: |
python -m pip install --upgrade pip
pip install -U platformio adafruit-nrfutil
pip install -U meshtastic --pre
- name: Upgrade platformio
run: |
pio upgrade
# We now run integration test before other build steps (to quickly see runtime failures) # We now run integration test before other build steps (to quickly see runtime failures)
- name: Build for native - name: Build for native
@@ -339,11 +127,29 @@ jobs:
with: with:
name: firmware-native-${{ steps.version.outputs.version }}.zip name: firmware-native-${{ steps.version.outputs.version }}.zip
path: | path: |
release/meshtasticd_linux_amd64
release/device-*.sh release/device-*.sh
release/device-*.bat release/device-*.bat
retention-days: 30
- name: Docker login
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: docker/login-action@v2
with:
username: meshtastic
password: ${{ secrets.DOCKER_TOKEN }}
- name: Docker setup
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: docker/setup-buildx-action@v2
- name: Docker build and push
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: docker/build-push-action@v3
with:
context: .
file: ./Dockerfile
push: true
tags: meshtastic/device-simulator:latest
after-checks: after-checks:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [check] needs: [check]
@@ -373,7 +179,7 @@ jobs:
id: version id: version
- name: Move files up - 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 ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat 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
- name: Repackage in single firmware zip - name: Repackage in single firmware zip
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -383,7 +189,6 @@ jobs:
./*.bin ./*.bin
./*.uf2 ./*.uf2
./firmware-*-ota.zip ./firmware-*-ota.zip
./meshtasticd_linux_amd64
./device-*.sh ./device-*.sh
./device-*.bat ./device-*.bat
retention-days: 90 retention-days: 90
@@ -403,7 +208,7 @@ jobs:
chmod +x ./output/device-update.sh chmod +x ./output/device-update.sh
- name: Zip firmware - name: Zip firmware
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
- name: Repackage in single elfs zip - name: Repackage in single elfs zip
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -452,7 +257,7 @@ jobs:
chmod +x ./output/device-update.sh chmod +x ./output/device-update.sh
- name: Zip firmware - name: Zip firmware
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v3
with: with:
@@ -460,7 +265,7 @@ jobs:
path: ./elfs path: ./elfs
- name: Zip Elfs - name: Zip Elfs
run: zip -j -r ./debug-elfs-${{ steps.version.outputs.version }}.zip ./elfs run: zip -j -9 -r ./debug-elfs-${{ steps.version.outputs.version }}.zip ./elfs
# For diagnostics # For diagnostics
- name: Show artifacts - name: Show artifacts

View File

@@ -0,0 +1,40 @@
---
name: Flawfinder Scan
on:
push:
branches: [master, develop]
paths-ignore:
- "**.md"
- "version.properties"
jobs:
flawfinder:
runs-on: ubuntu-latest
name: Flawfinder
steps:
# step 1
- name: clone application source code
uses: actions/checkout@v3
# step 2
- name: flawfinder_scan
uses: david-a-wheeler/flawfinder@2.0.19
with:
arguments: '--sarif ./'
output: 'flawfinder_report.sarif'
# step 3
- name: save report as pipeline artifact
uses: actions/upload-artifact@v3
with:
name: flawfinder_report.sarif
path: flawfinder_report.sarif
# step 4
- name: publish code scanning alerts
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: flawfinder_report.sarif
category: flawfinder

View File

@@ -0,0 +1,44 @@
---
name: Semgrep Full Scan
on:
workflow_dispatch:
branches:
- master
schedule:
- cron: '0 1 * * 6'
jobs:
semgrep-full:
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
steps:
# step 1
- name: clone application source code
uses: actions/checkout@v3
# step 2
- name: full scan
run: |
semgrep \
--sarif --output report.sarif \
--metrics=off \
--config="p/default"
# step 3
- name: save report as pipeline artifact
uses: actions/upload-artifact@v3
with:
name: report.sarif
path: report.sarif
# step 4
- name: publish code scanning alerts
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: report.sarif
category: semgrep

View File

@@ -0,0 +1,28 @@
---
name: Semgrep Differential Scan
on:
pull_request
jobs:
semgrep-diff:
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
steps:
# step 1
- name: clone application source code
uses: actions/checkout@v3
with:
fetch-depth: 0
# step 2
- name: differential scan
run: |
semgrep scan \
--error \
--metrics=off \
--baseline-commit ${{ github.event.pull_request.base.sha }} \
--config="p/default"

View File

@@ -17,9 +17,9 @@ jobs:
- name: Download nanopb - name: Download nanopb
run: | run: |
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.6-linux-x86.tar.gz wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.7-linux-x86.tar.gz
tar xvzf nanopb-0.4.6-linux-x86.tar.gz tar xvzf nanopb-0.4.7-linux-x86.tar.gz
mv nanopb-0.4.6-linux-x86 nanopb-0.4.6 mv nanopb-0.4.7-linux-x86 nanopb-0.4.7
- name: Re-generate protocol buffers - name: Re-generate protocol buffers
run: | run: |

1
.gitignore vendored
View File

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

1
.gitmodules vendored
View File

@@ -1,4 +1,3 @@
[submodule "protobufs"] [submodule "protobufs"]
path = protobufs path = protobufs
url = https://github.com/meshtastic/protobufs.git url = https://github.com/meshtastic/protobufs.git
branch = develop

2
.semgrepignore Normal file
View File

@@ -0,0 +1,2 @@
.github/workflows/main_matrix.yml
src/mesh/compression/unishox2.c

View File

@@ -1,15 +1,41 @@
FROM debian:bullseye-slim AS builder FROM debian:bullseye-slim AS builder
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install wget python3 g++ zip python3-venv git vim ENV DEBIAN_FRONTEND=noninteractive
RUN wget https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py -O get-platformio.py; chmod +x get-platformio.py ENV TZ=Etc/UTC
RUN python3 get-platformio.py
RUN git clone https://github.com/meshtastic/firmware --recurse-submodules # http://bugs.python.org/issue19846
RUN cd firmware # > At the moment, setting "LANG=C" on a Linux system *fundamentally breaks Python 3*, and that's not OK.
RUN chmod +x ./firmware/bin/build-native.sh ENV LANG C.UTF-8
RUN . ~/.platformio/penv/bin/activate; cd firmware; sh ./bin/build-native.sh
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Install build deps
USER root
RUN apt-get update && \
apt-get -y install wget python3 g++ zip python3-venv git vim ca-certificates
# create a non-priveleged user & group
RUN groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh
USER mesh
RUN wget https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py -qO /tmp/get-platformio.py && \
chmod +x /tmp/get-platformio.py && \
python3 /tmp/get-platformio.py && \
git clone https://github.com/meshtastic/firmware --recurse-submodules /tmp/firmware && \
cd /tmp/firmware && \
chmod +x /tmp/firmware/bin/build-native.sh && \
source ~/.platformio/penv/bin/activate && \
./bin/build-native.sh
FROM frolvlad/alpine-glibc FROM frolvlad/alpine-glibc
WORKDIR /root/
COPY --from=builder /firmware/release/meshtasticd_linux_amd64 ./ RUN apk --update add --no-cache g++ shadow && \
RUN apk --update add --no-cache g++ groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh
CMD sh -cx "./meshtasticd_linux_amd64 --hwid '$RANDOM'"
COPY --from=builder /tmp/firmware/release/meshtasticd_linux_amd64 /home/mesh/
USER mesh
WORKDIR /home/mesh
CMD sh -cx "./meshtasticd_linux_amd64 --hwid '$RANDOM'"
HEALTHCHECK NONE

View File

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

View File

@@ -26,14 +26,16 @@ build_flags =
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DDEBUG_HEAP
lib_deps = lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
${networking_base.lib_deps} ${networking_base.lib_deps}
${environmental_base.lib_deps} ${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#657509856ce97e9dddeffb89a559f544faefd5cd https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0 h2zero/NimBLE-Arduino@^1.4.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6 https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
caveman99/ESP32 Codec2@^1.0.1
lib_ignore = lib_ignore =
segger_rtt segger_rtt

47
arch/esp32/esp32s2.ini Normal file
View File

@@ -0,0 +1,47 @@
[esp32s2_base]
extends = arduino_base
platform = platformio/espressif32@^5.2.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<nimble/>
upload_speed = 961200
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
-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

View File

@@ -23,17 +23,19 @@ build_flags =
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DAXP_DEBUG_PORT=Serial -DAXP_DEBUG_PORT=Serial
-DCONFIG_BT_NIMBLE_ENABLED -DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DDEBUG_HEAP
lib_deps = lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
${networking_base.lib_deps} ${networking_base.lib_deps}
${environmental_base.lib_deps} ${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#657509856ce97e9dddeffb89a559f544faefd5cd https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0 h2zero/NimBLE-Arduino@^1.4.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6 https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
caveman99/ESP32 Codec2@^1.0.1
lib_ignore = lib_ignore =
segger_rtt segger_rtt

View File

@@ -1,5 +1,7 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated ; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base] [portduino_base]
platform = https://github.com/meshtastic/platform-native.git#096b3c3e9c5c8e19d4c3b6cd803fffef2a9be4c5
framework = arduino
build_src_filter = build_src_filter =
${env.build_src_filter} ${env.build_src_filter}
-<platform/esp32/> -<platform/esp32/>
@@ -16,5 +18,4 @@ lib_deps =
${env.lib_deps} ${env.lib_deps}
${networking_base.lib_deps} ${networking_base.lib_deps}
rweather/Crypto@^0.4.0 rweather/Crypto@^0.4.0
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
build_flags = ${arduino_base.build_flags} -Isrc/platform/portduino build_flags = ${arduino_base.build_flags} -Isrc/platform/portduino

View File

@@ -10,9 +10,6 @@ OUTDIR=release/
rm -f $OUTDIR/firmware* rm -f $OUTDIR/firmware*
rm -r $OUTDIR/* || true rm -r $OUTDIR/* || true
# Make sure our submodules are current
git submodule update
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio pkg update platformio pkg update
@@ -32,6 +29,10 @@ echo "Copying ESP32 bin file"
SRCBIN=.pio/build/$1/firmware.factory.bin SRCBIN=.pio/build/$1/firmware.factory.bin
cp $SRCBIN $OUTDIR/$basename.bin cp $SRCBIN $OUTDIR/$basename.bin
echo "Copying ESP32 update bin file"
SRCBIN=.pio/build/$1/firmware.bin
cp $SRCBIN $OUTDIR/$basename-update.bin
echo "Building Filesystem for ESP32 targets" echo "Building Filesystem for ESP32 targets"
pio run --environment tbeam -t buildfs pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin

View File

@@ -12,9 +12,6 @@ rm -f $OUTDIR/firmware*
mkdir -p $OUTDIR/ mkdir -p $OUTDIR/
rm -r $OUTDIR/* || true rm -r $OUTDIR/* || true
# Make sure our submodules are current
git submodule update
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio pkg update platformio pkg update

View File

@@ -10,9 +10,6 @@ OUTDIR=release/
rm -f $OUTDIR/firmware* rm -f $OUTDIR/firmware*
rm -r $OUTDIR/* || true rm -r $OUTDIR/* || true
# Make sure our submodules are current
git submodule update
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio pkg update platformio pkg update

View File

@@ -10,9 +10,6 @@ OUTDIR=release/
rm -f $OUTDIR/firmware* rm -f $OUTDIR/firmware*
rm -r $OUTDIR/* || true rm -r $OUTDIR/* || true
# Make sure our submodules are current
git submodule update
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio pkg update platformio pkg update

View File

@@ -26,7 +26,7 @@ IF "__%FILENAME%__" == "____" (
echo "Missing FILENAME" echo "Missing FILENAME"
goto HELP goto HELP
) )
IF EXIST %FILENAME% ( IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
echo Trying to flash update %FILENAME%, but first erasing and writing system information" 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 erase_flash
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME% %PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
@@ -37,6 +37,9 @@ IF EXIST %FILENAME% (
) else ( ) else (
echo "Invalid file: %FILENAME%" echo "Invalid file: %FILENAME%"
goto HELP goto HELP
) else (
echo "Invalid file: %FILENAME%"
goto HELP
) )
:EOF :EOF

View File

@@ -14,6 +14,7 @@ Flash image file to device, but first erasing and writing system information"
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous). -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON") -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
-f FILENAME The .bin file to flash. Custom to your device type and region. -f FILENAME The .bin file to flash. Custom to your device type and region.
EOF EOF
} }
@@ -44,7 +45,7 @@ shift "$((OPTIND-1))"
shift shift
} }
if [ -f "${FILENAME}" ]; then if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information" echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash "$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME} "$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
@@ -52,8 +53,8 @@ if [ -f "${FILENAME}" ]; then
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin "$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
else else
echo "Invalid file: ${FILENAME}"
show_help show_help
echo "Invalid file: ${FILENAME}"
fi fi
exit 0 exit 0

View File

@@ -10,7 +10,7 @@ echo.
echo -h Display this help and exit echo -h Display this help and exit
echo -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous). echo -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
echo -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: %PYTHON%) echo -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: %PYTHON%)
echo -f FILENAME The .bin file to flash. Custom to your device type and region. echo -f FILENAME The *update.bin file to flash. Custom to your device type.
goto EOF goto EOF
:GETOPTS :GETOPTS
@@ -26,9 +26,12 @@ IF "__%FILENAME%__" == "____" (
echo "Missing FILENAME" echo "Missing FILENAME"
goto HELP goto HELP
) )
IF EXIST %FILENAME% ( IF EXIST %FILENAME% IF NOT x%FILENAME:update=%==x%FILENAME% (
echo Trying to flash update %FILENAME% echo Trying to flash update %FILENAME%
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME% %PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
) else (
echo "Invalid file: %FILENAME%"
goto HELP
) else ( ) else (
echo "Invalid file: %FILENAME%" echo "Invalid file: %FILENAME%"
goto HELP goto HELP

View File

@@ -11,7 +11,8 @@ Flash image file to device, leave existing system intact."
-h Display this help and exit -h Display this help and exit
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous). -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON") -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
-f FILENAME The .bin file to flash. Custom to your device type and region. -f FILENAME The *update.bin file to flash. Custom to your device type.
EOF EOF
} }
@@ -42,12 +43,12 @@ shift "$((OPTIND-1))"
shift shift
} }
if [ -f "${FILENAME}" ]; then if [ -f "${FILENAME}" ] && [ -z "${FILENAME##*"update"*}" ]; then
echo "Trying to flash update ${FILENAME}." printf "Trying to flash update ${FILENAME}"
$PYTHON -m esptool --baud 115200 write_flash 0x00 ${FILENAME} $PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME}
else else
echo "Invalid file: ${FILENAME}"
show_help show_help
echo "Invalid file: ${FILENAME}"
fi fi
exit 0 exit 0

View File

@@ -1 +1 @@
cd protobufs && ..\nanopb-0.4.6\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto

View File

@@ -2,13 +2,13 @@
set -e set -e
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.6 to be located in the" echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.7 to be located in the"
echo "firmware root directory if the following step fails, you should download the correct" echo "firmware root directory if the following step fails, you should download the correct"
echo "prebuilt binaries for your computer into nanopb-0.4.6" 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! # the nanopb tool seems to require that the .options file be in the current directory!
cd protobufs cd protobufs
../nanopb-0.4.6/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto ../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto
#echo "Regenerating protobuf documentation - if you see an error message" #echo "Regenerating protobuf documentation - if you see an error message"
#echo "you can ignore it unless doing a new protobuf release to github." #echo "you can ignore it unless doing a new protobuf release to github."

View File

@@ -1,6 +1,6 @@
{ {
"build": { "build": {
"arduino":{ "arduino": {
"ldscript": "esp32s3_out.ld" "ldscript": "esp32s3_out.ld"
}, },
"core": "esp32", "core": "esp32",
@@ -8,9 +8,7 @@
"-DBOARD_HAS_PSRAM", "-DBOARD_HAS_PSRAM",
"-DLILYGO_TBEAM_S3_CORE", "-DLILYGO_TBEAM_S3_CORE",
"-DARDUINO_USB_CDC_ON_BOOT=1", "-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_DFU_ON_BOOT=1", "-DARDUINO_USB_MODE=0",
"-DARDUINO_USB_MSC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_RUNNING_CORE=1", "-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1" "-DARDUINO_EVENT_RUNNING_CORE=1"
], ],
@@ -45,4 +43,4 @@
}, },
"url": "http://www.lilygo.cn/", "url": "http://www.lilygo.cn/",
"vendor": "LilyGo" "vendor": "LilyGo"
} }

View File

@@ -5,7 +5,7 @@ services:
build: . build: .
deploy: deploy:
mode: replicated mode: replicated
replicas: 80 replicas: 4
networks: networks:
- mesh - mesh

View File

@@ -37,12 +37,24 @@ extra_scripts = bin/platformio-custom.py
; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile ; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile
; of code is a heap corruption bug! ; of code is a heap corruption bug!
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc ; 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 build_flags = -Wno-missing-field-initializers
-Wno-format -Wno-format
-Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map -Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
-DUSE_THREAD_NAMES -DUSE_THREAD_NAMES
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS -DTINYGPS_OPTION_NO_CUSTOM_FIELDS
-DPB_ENABLE_MALLOC=1 -DPB_ENABLE_MALLOC=1
-DRADIOLIB_EXCLUDE_CC1101
-DRADIOLIB_EXCLUDE_NRF24
-DRADIOLIB_EXCLUDE_RF69
-DRADIOLIB_EXCLUDE_SX1231
-DRADIOLIB_EXCLUDE_SI443X
-DRADIOLIB_EXCLUDE_RFM2X
-DRADIOLIB_EXCLUDE_AFSK
-DRADIOLIB_EXCLUDE_HELLSCHREIBER
-DRADIOLIB_EXCLUDE_MORSE
-DRADIOLIB_EXCLUDE_RTTY
-DRADIOLIB_EXCLUDE_SSTV
monitor_speed = 115200 monitor_speed = 115200
@@ -50,10 +62,11 @@ lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#53580644255b48ebb7a737343c6b4e71c7e11cf2 ; ESP8266_SSD1306 https://github.com/meshtastic/esp8266-oled-ssd1306.git#53580644255b48ebb7a737343c6b4e71c7e11cf2 ; ESP8266_SSD1306
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#2f0d0528d737000043e949f4c3bdfb623cf0b902 https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3 https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.6 nanopb/Nanopb@^0.4.6
erriez/ErriezCRC32@^1.0.1 erriez/ErriezCRC32@^1.0.1
jgromes/RadioLib@^5.5.0
; Used for the code analysis in PIO Home / Inspect ; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck check_tool = cppcheck
@@ -61,19 +74,17 @@ check_skip_packages = yes
check_flags = check_flags =
-DAPP_VERSION=1.0.0 -DAPP_VERSION=1.0.0
--suppressions-list=suppressions.txt --suppressions-list=suppressions.txt
--inline-suppr
; Common settings for conventional (non Portduino) Arduino targets ; Common settings for conventional (non Portduino) Arduino targets
[arduino_base] [arduino_base]
framework = arduino framework = arduino
lib_deps = lib_deps =
${env.lib_deps} ${env.lib_deps}
; Portduino is using meshtastic fork for now mprograms/QMC5883LCompass@^1.1.1
jgromes/RadioLib@5.4.1
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76 https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
build_flags = ${env.build_flags} -Os build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
-DRADIOLIB_SPI_PARANOID=0
# -DRADIOLIB_GODMODE
build_src_filter = ${env.build_src_filter} -<platform/portduino/> build_src_filter = ${env.build_src_filter} -<platform/portduino/>
; Common libs for communicating over TCP/IP networks such as MQTT ; Common libs for communicating over TCP/IP networks such as MQTT
@@ -81,7 +92,6 @@ build_src_filter = ${env.build_src_filter} -<platform/portduino/>
lib_deps = lib_deps =
knolleary/PubSubClient@^2.8 knolleary/PubSubClient@^2.8
arduino-libraries/NTPClient@^3.1.0 arduino-libraries/NTPClient@^3.1.0
meshtastic/json11@^1.0.2
; Common libs for environmental measurements in telemetry module ; Common libs for environmental measurements in telemetry module
; (not included in native / portduino) ; (not included in native / portduino)

View File

@@ -51,6 +51,7 @@ class ButtonThread : public concurrency::OSThread
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE); pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
#endif #endif
userButton.attachClick(userButtonPressed); userButton.attachClick(userButtonPressed);
userButton.setClickTicks(300);
userButton.attachDuringLongPress(userButtonPressedLong); userButton.attachDuringLongPress(userButtonPressedLong);
userButton.attachDoubleClick(userButtonDoublePressed); userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed); userButton.attachMultiClick(userButtonMultiPressed);
@@ -159,9 +160,21 @@ class ButtonThread : public concurrency::OSThread
static void userButtonDoublePressed() static void userButtonDoublePressed()
{ {
#if defined(USE_EINK) && defined(PIN_EINK_EN) #if defined(USE_EINK) && defined(PIN_EINK_EN)
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW); digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
#endif #endif
#if defined(GPS_POWER_TOGGLE)
if(config.position.gps_enabled)
{
DEBUG_MSG("Flag set to false for gps power\n");
}
else
{
DEBUG_MSG("Flag set to true to restore power\n");
}
config.position.gps_enabled = !(config.position.gps_enabled);
doGPSpowersave(config.position.gps_enabled);
#endif
} }
static void userButtonMultiPressed() static void userButtonMultiPressed()

View File

@@ -1,6 +1,18 @@
#include "configuration.h" #include "configuration.h"
#include "FSCommon.h" #include "FSCommon.h"
#ifdef HAS_SDCARD
#include <SPI.h>
#include <SD.h>
#ifdef SDCARD_USE_SPI1
SPIClass SPI1(HSPI);
#define SDHandler SPI1
#endif
#endif //HAS_SDCARD
bool copyFile(const char* from, const char* to) bool copyFile(const char* from, const char* to)
{ {
@@ -169,3 +181,39 @@ void fsInit()
listDir("/", 10); listDir("/", 10);
#endif #endif
} }
void setupSDCard()
{
#ifdef HAS_SDCARD
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
if (!SD.begin(SDCARD_CS, SDHandler)) {
DEBUG_MSG("No SD_MMC card detected\n");
return ;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
DEBUG_MSG("No SD_MMC card attached\n");
return ;
}
DEBUG_MSG("SD_MMC Card Type: ");
if (cardType == CARD_MMC) {
DEBUG_MSG("MMC\n");
} else if (cardType == CARD_SD) {
DEBUG_MSG("SDSC\n");
} else if (cardType == CARD_SDHC) {
DEBUG_MSG("SDHC\n");
} else {
DEBUG_MSG("UNKNOWN\n");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
DEBUG_MSG("SD Card Size: %lluMB\n", cardSize);
DEBUG_MSG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
DEBUG_MSG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
#endif
}

View File

@@ -44,3 +44,4 @@ bool copyFile(const char* from, const char* to);
bool renameFile(const char* pathFrom, const char* pathTo); 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, boolean del);
void rmDir(const char * dirname); void rmDir(const char * dirname);
void setupSDCard();

View File

@@ -20,32 +20,19 @@ class GPSStatus : public Status
bool hasLock = false; // default to false, until we complete our first read bool hasLock = false; // default to false, until we complete our first read
bool isConnected = false; // Do we have a GPS we are talking to bool isConnected = false; // Do we have a GPS we are talking to
bool isPowerSaving = false; //Are we in power saving state
Position p = Position_init_default; Position p = Position_init_default;
public: public:
GPSStatus() { statusType = STATUS_TYPE_GPS; } GPSStatus() { statusType = STATUS_TYPE_GPS; }
// // proposed for deprecation
// GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
// uint32_t heading, uint32_t numSatellites)
// : Status()
// {
// this->hasLock = hasLock;
// this->isConnected = isConnected;
// this->p.latitude_i = latitude;
// this->p.longitude_i = longitude;
// this->p.altitude = altitude;
// this->p.PDOP = dop;
// this->p.ground_track = heading;
// this->p.sats_in_view = numSatellites;
// }
// preferred method // preferred method
GPSStatus(bool hasLock, bool isConnected, const Position &pos) : Status() GPSStatus(bool hasLock, bool isConnected, bool isPowerSaving, const Position &pos) : Status()
{ {
this->hasLock = hasLock; this->hasLock = hasLock;
this->isConnected = isConnected; this->isConnected = isConnected;
this->isPowerSaving = isPowerSaving;
// all-in-one struct copy // all-in-one struct copy
this->p = pos; this->p = pos;
@@ -60,6 +47,8 @@ class GPSStatus : public Status
bool getIsConnected() const { return isConnected; } bool getIsConnected() const { return isConnected; }
bool getIsPowerSaving() const { return isPowerSaving;}
int32_t getLatitude() const int32_t getLatitude() const
{ {
if (config.position.fixed_position) { if (config.position.fixed_position) {
@@ -110,7 +99,7 @@ class GPSStatus : public Status
#ifdef GPS_EXTRAVERBOSE #ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp); DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp);
#endif #endif
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->isPowerSaving !=isPowerSaving ||
newStatus->p.latitude_i != p.latitude_i || newStatus->p.longitude_i != p.longitude_i || newStatus->p.latitude_i != p.latitude_i || newStatus->p.longitude_i != p.longitude_i ||
newStatus->p.altitude != p.altitude || newStatus->p.altitude_hae != p.altitude_hae || newStatus->p.altitude != p.altitude || newStatus->p.altitude_hae != p.altitude_hae ||
newStatus->p.PDOP != p.PDOP || newStatus->p.ground_track != p.ground_track || newStatus->p.PDOP != p.PDOP || newStatus->p.ground_track != p.ground_track ||

View File

@@ -102,6 +102,10 @@ class AnalogBatteryLevel : public HasBatteryLevel
#define ADC_MULTIPLIER 2.0 #define ADC_MULTIPLIER 2.0
#endif #endif
#ifndef BATTERY_SENSE_SAMPLES
#define BATTERY_SENSE_SAMPLES 30
#endif
#ifdef BATTERY_PIN #ifdef BATTERY_PIN
// Override variant or default ADC_MULTIPLIER if we have the override pref // Override variant or default ADC_MULTIPLIER if we have the override pref
float operativeAdcMultiplier = config.power.adc_multiplier_override > 0 float operativeAdcMultiplier = config.power.adc_multiplier_override > 0
@@ -112,16 +116,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
if (millis() - last_read_time_ms > min_read_interval) { if (millis() - last_read_time_ms > min_read_interval) {
last_read_time_ms = millis(); last_read_time_ms = millis();
#ifdef BATTERY_SENSE_SAMPLES
//Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic environment. //Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic environment.
uint32_t raw = 0; uint32_t raw = 0;
for(uint32_t i=0; i<BATTERY_SENSE_SAMPLES;i++){ for(uint32_t i=0; i<BATTERY_SENSE_SAMPLES; i++){
raw += analogRead(BATTERY_PIN); raw += analogRead(BATTERY_PIN);
} }
raw = raw/BATTERY_SENSE_SAMPLES; raw = raw/BATTERY_SENSE_SAMPLES;
#else
uint32_t raw = analogRead(BATTERY_PIN);
#endif
float scaled; float scaled;
#ifndef VBAT_RAW_TO_SCALED #ifndef VBAT_RAW_TO_SCALED
@@ -182,6 +182,9 @@ Power::Power() : OSThread("Power")
{ {
statusHandler = {}; statusHandler = {};
low_voltage_counter = 0; low_voltage_counter = 0;
#ifdef DEBUG_HEAP
lastheap = ESP.getFreeHeap();
#endif
} }
bool Power::analogInit() bool Power::analogInit()
@@ -283,6 +286,12 @@ void Power::readPowerStatus()
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(), DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent()); powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2); newStatus.notifyObservers(&powerStatus2);
#ifdef DEBUG_HEAP
if (lastheap != ESP.getFreeHeap()){
DEBUG_MSG("Heap status: %d/%d bytes free (%d), running %d threads\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreeHeap() - lastheap , concurrency::mainController.size(false));
lastheap = ESP.getFreeHeap();
}
#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 // 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 // Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
@@ -290,8 +299,12 @@ void Power::readPowerStatus()
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) { if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) { if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) {
low_voltage_counter++; low_voltage_counter++;
if (low_voltage_counter > 3) DEBUG_MSG("Warning RAK4631 Low voltage counter: %d/10\n", low_voltage_counter);
powerFSM.trigger(EVENT_LOW_BATTERY); if (low_voltage_counter > 10) {
// We can't trigger deep sleep on NRF52, it's freezing the board
//powerFSM.trigger(EVENT_LOW_BATTERY);
DEBUG_MSG("Low voltage detected, but not triggering deep sleep\n");
}
} else { } else {
low_voltage_counter = 0; low_voltage_counter = 0;
} }
@@ -455,6 +468,9 @@ bool Power::axpChipInit()
// Set constant current charging current // Set constant current charging current
PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_450MA); PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_450MA);
//Set up the charging voltage
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
} else if (PMU->getChipModel() == XPOWERS_AXP2101) { } else if (PMU->getChipModel() == XPOWERS_AXP2101) {
// t-beam s3 core // t-beam s3 core
@@ -507,6 +523,8 @@ bool Power::axpChipInit()
//Set the constant current charging current of AXP2101, temporarily use 500mA by default //Set the constant current charging current of AXP2101, temporarily use 500mA by default
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA); PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
//Set up the charging voltage
PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
} }
@@ -559,14 +577,15 @@ bool Power::axpChipInit()
} }
DEBUG_MSG("=======================================================================\n"); DEBUG_MSG("=======================================================================\n");
// We can safely ignore this approach for most (or all) boards because MCU turned off
//Set up the charging voltage, AXP2101/AXP192 4.2V gear is the same // earlier than battery discharged to 2.6V.
// XPOWERS_AXP192_CHG_VOL_4V2 = XPOWERS_AXP2101_CHG_VOL_4V2 //
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2); // Unfortanly for now we can't use this killswitch for RAK4630-based boards because they have a bug with
// battery voltage measurement. Probably it sometimes drops to low values.
#ifndef RAK4630
// Set PMU shutdown voltage at 2.6V to maximize battery utilization // Set PMU shutdown voltage at 2.6V to maximize battery utilization
PMU->setSysPowerDownVoltage(2600); PMU->setSysPowerDownVoltage(2600);
#endif
#ifdef PMU_IRQ #ifdef PMU_IRQ

View File

@@ -34,7 +34,7 @@ static void sdsEnter()
{ {
DEBUG_MSG("Enter state: SDS\n"); DEBUG_MSG("Enter state: SDS\n");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
doDeepSleep(config.power.sds_secs * 1000); doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs));
} }
extern Power *power; extern Power *power;
@@ -324,31 +324,24 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone"); powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
// each time we get a new update packet make sure we are staying in the ON state so the screen stays awake (also we don't
// shutdown bluetooth if is_router)
powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout"); powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout");
#ifdef ARCH_ESP32
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK // On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS; State *lowPowerState = &stateLS;
#ifdef ARCH_ESP32
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
// See: https://github.com/meshtastic/firmware/issues/1071 // See: https://github.com/meshtastic/firmware/issues/1071
if (isRouter || config.power.is_power_saving) { if (isRouter || config.power.is_power_saving) {
powerFSM.add_timed_transition(&stateNB, &stateLS, getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout"); powerFSM.add_timed_transition(&stateNB, &stateLS, getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL, "Bluetooth timeout"); powerFSM.add_timed_transition(&stateDARK, &stateLS, getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL, "Bluetooth timeout");
} }
#elif defined (ARCH_NRF52)
lowPowerState = &stateDARK;
#endif
if (config.power.sds_secs != UINT32_MAX) if (config.power.sds_secs != UINT32_MAX)
powerFSM.add_timed_transition(lowPowerState, &stateSDS, config.power.sds_secs * 1000, NULL, "mesh timeout"); powerFSM.add_timed_transition(lowPowerState, &stateSDS, getConfiguredOrDefaultMs(config.power.sds_secs), NULL, "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 interation of the state machine, so we run our on enter tasks for the initial DARK state
} }

View File

@@ -26,11 +26,9 @@ class PowerFSMThread : public OSThread
if (powerStatus->getHasUSB()) { if (powerStatus->getHasUSB()) {
timeLastPowered = millis(); timeLastPowered = millis();
} else if (config.power.on_battery_shutdown_after_secs > 0 && } else if (config.power.on_battery_shutdown_after_secs > 0 &&
millis() > config.power.on_battery_shutdown_after_secs != UINT32_MAX &&
timeLastPowered + millis() > (timeLastPowered + getConfiguredOrDefaultMs(config.power.on_battery_shutdown_after_secs))) { // shutdown after 30 minutes unpowered
(1000 *
config.power.on_battery_shutdown_after_secs)) { // shutdown after 30 minutes unpowered
powerFSM.trigger(EVENT_SHUTDOWN); powerFSM.trigger(EVENT_SHUTDOWN);
} }

View File

@@ -117,6 +117,20 @@ float AirTime::utilizationTXPercent()
return (float(sum) / float(MS_IN_HOUR)) * 100; return (float(sum) / float(MS_IN_HOUR)) * 100;
} }
// Get the amount of minutes we have to be silent before we can send again
uint8_t AirTime::getSilentMinutes(float txPercent, float dutyCycle)
{
float newTxPercent = txPercent;
for (int8_t i = MINUTES_IN_HOUR-1; i >= 0; --i) {
newTxPercent -= ((float)this->utilizationTX[i] / (MS_IN_MINUTE * MINUTES_IN_HOUR / 100));
if (newTxPercent < dutyCycle)
return MINUTES_IN_HOUR-1-i;
}
return MINUTES_IN_HOUR;
}
AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) { AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) {
} }

View File

@@ -29,6 +29,7 @@
#define PERIODS_TO_LOG 8 #define PERIODS_TO_LOG 8
#define MINUTES_IN_HOUR 60 #define MINUTES_IN_HOUR 60
#define SECONDS_IN_MINUTE 60 #define SECONDS_IN_MINUTE 60
#define MS_IN_MINUTE (SECONDS_IN_MINUTE * 1000)
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000) #define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)
@@ -57,6 +58,7 @@ class AirTime : private concurrency::OSThread
uint32_t getSecondsPerPeriod(); uint32_t getSecondsPerPeriod();
uint32_t getSecondsSinceBoot(); uint32_t getSecondsSinceBoot();
uint32_t *airtimeReport(reportTypes reportType); uint32_t *airtimeReport(reportTypes reportType);
uint8_t getSilentMinutes(float txPercent, float dutyCycle);
private: private:
bool firstTime = true; bool firstTime = true;

View File

@@ -2,22 +2,13 @@
#include "configuration.h" #include "configuration.h"
#include "NodeDB.h" #include "NodeDB.h"
#ifndef PIN_BUZZER #if !defined(ARCH_ESP32) && !defined(ARCH_RP2040) && !defined(ARCH_PORTDUINO)
// Noop methods for boards w/o buzzer
void playBeep(){};
void playStartMelody(){};
void playShutdownMelody(){};
#else
#ifdef M5STACK
#include "Speaker.h"
TONE Tone;
#else
#include "Tone.h" #include "Tone.h"
#endif #endif
#if !defined(ARCH_PORTDUINO)
extern "C" void delay(uint32_t dwMs); extern "C" void delay(uint32_t dwMs);
#endif
struct ToneDuration { struct ToneDuration {
int frequency_khz; int frequency_khz;
@@ -43,30 +34,25 @@ const int DURATION_1_8 = 125; // 1/8 note
const int DURATION_1_4 = 250; // 1/4 note const int DURATION_1_4 = 250; // 1/4 note
void playTones(const ToneDuration *tone_durations, int size) { void playTones(const ToneDuration *tone_durations, int size) {
if (config.network.eth_enabled != true) { #ifdef PIN_BUZZER
if (!config.device.buzzer_gpio)
config.device.buzzer_gpio = PIN_BUZZER;
#endif
if (config.device.buzzer_gpio) {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
const auto &tone_duration = tone_durations[i]; const auto &tone_duration = tone_durations[i];
#ifdef M5STACK tone(config.device.buzzer_gpio, tone_duration.frequency_khz, tone_duration.duration_ms);
Tone.tone(tone_duration.frequency_khz);
delay(tone_duration.duration_ms);
Tone.mute();
#else
tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms);
#endif
// to distinguish the notes, set a minimum time between them. // to distinguish the notes, set a minimum time between them.
delay(1.3 * tone_duration.duration_ms); delay(1.3 * tone_duration.duration_ms);
} }
} }
} }
#ifdef M5STACK
void playBeep() { void playBeep() {
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}}; ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration)); playTones(melody, sizeof(melody) / sizeof(ToneDuration));
} }
#else
void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); }
#endif
void playStartMelody() { void playStartMelody() {
ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8}, ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8},
@@ -75,11 +61,9 @@ void playStartMelody() {
playTones(melody, sizeof(melody) / sizeof(ToneDuration)); playTones(melody, sizeof(melody) / sizeof(ToneDuration));
} }
void playShutdownMelody() { void playShutdownMelody() {
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8}, ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8},
{NOTE_AS3, DURATION_1_8}, {NOTE_AS3, DURATION_1_8},
{NOTE_FS3, DURATION_1_4}}; {NOTE_FS3, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration)); playTones(melody, sizeof(melody) / sizeof(ToneDuration));
} }
#endif

View File

@@ -110,6 +110,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define INA_ADDR_ALTERNATE 0x41 #define INA_ADDR_ALTERNATE 0x41
#define QMC6310_ADDR 0x1C #define QMC6310_ADDR 0x1C
#define QMI8658_ADDR 0x6B #define QMI8658_ADDR 0x6B
#define QMC5883L_ADDR 0x1E
#define SHTC3_ADDR 0x70 #define SHTC3_ADDR 0x70
#define LPS22HB_ADDR 0x5C #define LPS22HB_ADDR 0x5C
#define LPS22HB_ADDR_ALT 0x5D #define LPS22HB_ADDR_ALT 0x5D

View File

@@ -12,7 +12,7 @@
void printATECCInfo() void printATECCInfo()
{ {
#ifndef ARCH_PORTDUINO #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
atecc.readConfigZone(false); atecc.readConfigZone(false);
DEBUG_MSG("ATECC608B Serial Number: "); DEBUG_MSG("ATECC608B Serial Number: ");
@@ -90,7 +90,7 @@ uint8_t oled_probe(byte addr)
return o_probe; return o_probe;
} }
void scanI2Cdevice(void) void scanI2Cdevice()
{ {
byte err, addr; byte err, addr;
uint16_t registerValue = 0x00; uint16_t registerValue = 0x00;
@@ -106,16 +106,16 @@ void scanI2Cdevice(void)
if (addr == SSD1306_ADDRESS) { if (addr == SSD1306_ADDRESS) {
screen_found = addr; screen_found = addr;
screen_model = oled_probe(addr); screen_model = oled_probe(addr);
if (screen_model == 1){ if (screen_model == 1) {
DEBUG_MSG("ssd1306 display found\n"); DEBUG_MSG("ssd1306 display found\n");
} else if (screen_model == 2){ } else if (screen_model == 2) {
DEBUG_MSG("sh1106 display found\n"); DEBUG_MSG("sh1106 display found\n");
} else { } else {
DEBUG_MSG("unknown display found\n"); DEBUG_MSG("unknown display found\n");
} }
} }
#ifndef ARCH_PORTDUINO #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
if (addr == ATECC608B_ADDR){ if (addr == ATECC608B_ADDR) {
keystore_found = addr; keystore_found = addr;
if (atecc.begin(keystore_found) == true) { if (atecc.begin(keystore_found) == true) {
DEBUG_MSG("ATECC608B initialized\n"); DEBUG_MSG("ATECC608B initialized\n");
@@ -163,50 +163,56 @@ void scanI2Cdevice(void)
DEBUG_MSG("axp192/axp2101 PMU found\n"); DEBUG_MSG("axp192/axp2101 PMU found\n");
} }
#endif #endif
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) { if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
if (registerValue == 0x61) { if (registerValue == 0x61) {
DEBUG_MSG("BME-680 sensor found at address 0x%x\n", (uint8_t)addr); DEBUG_MSG("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr; nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr;
} else if (registerValue == 0x60) { } else if (registerValue == 0x60) {
DEBUG_MSG("BME-280 sensor found at address 0x%x\n", (uint8_t)addr); DEBUG_MSG("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr; nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr;
} else { } else {
DEBUG_MSG("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr); DEBUG_MSG("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BMP280] = addr; nodeTelemetrySensorsMap[TelemetrySensorType_BMP280] = addr;
}
} }
} if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) { registerValue = getRegisterValue(addr, 0xFE, 2);
registerValue = getRegisterValue(addr, 0xFE, 2); DEBUG_MSG("Register MFG_UID: 0x%x\n", registerValue);
DEBUG_MSG("Register MFG_UID: 0x%x\n", registerValue); if (registerValue == 0x5449) {
if (registerValue == 0x5449) { DEBUG_MSG("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
DEBUG_MSG("INA260 sensor found at address 0x%x\n", (uint8_t)addr); nodeTelemetrySensorsMap[TelemetrySensorType_INA260] = addr;
nodeTelemetrySensorsMap[TelemetrySensorType_INA260] = addr; } else { // Assume INA219 if INA260 ID is not found
} else { // Assume INA219 if INA260 ID is not found DEBUG_MSG("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
DEBUG_MSG("INA219 sensor found at address 0x%x\n", (uint8_t)addr); nodeTelemetrySensorsMap[TelemetrySensorType_INA219] = addr;
nodeTelemetrySensorsMap[TelemetrySensorType_INA219] = addr; }
}
if (addr == MCP9808_ADDR) {
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
DEBUG_MSG("MCP9808 sensor found\n");
}
if (addr == SHTC3_ADDR) {
DEBUG_MSG("SHTC3 sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_SHTC3] = addr;
}
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
DEBUG_MSG("LPS22HB sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_LPS22] = addr;
}
// High rate sensors, will be processed internally
if (addr == QMC6310_ADDR) {
DEBUG_MSG("QMC6310 Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_QMC6310] = addr;
}
if (addr == QMI8658_ADDR) {
DEBUG_MSG("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658] = addr;
}
if (addr == QMC5883L_ADDR) {
DEBUG_MSG("QMC5883L Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_QMC5883L] = addr;
} }
}
if (addr == MCP9808_ADDR) {
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
DEBUG_MSG("MCP9808 sensor found at address 0x%x\n", (uint8_t)addr);
}
if (addr == QMC6310_ADDR) {
DEBUG_MSG("QMC6310 3-Axis magnetic sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_QMC6310] = addr;
}
if (addr == QMI8658_ADDR) {
DEBUG_MSG("QMI8658 6-Axis inertial measurement sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658] = addr;
}
if (addr == SHTC3_ADDR) {
DEBUG_MSG("SHTC3 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_SHTC3] = addr;
}
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
DEBUG_MSG("LPS22HB sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_LPS22] = addr;
}
} else if (err == 4) { } else if (err == 4) {
DEBUG_MSG("Unknow error at address 0x%x\n", addr); DEBUG_MSG("Unknow error at address 0x%x\n", addr);
} }
@@ -218,5 +224,5 @@ void scanI2Cdevice(void)
DEBUG_MSG("%i I2C devices found\n",nDevices); DEBUG_MSG("%i I2C devices found\n",nDevices);
} }
#else #else
void scanI2Cdevice(void) {} void scanI2Cdevice() {}
#endif #endif

View File

@@ -150,9 +150,21 @@ bool GPS::setupGPS()
_serial_gps->setRxBufferSize(2048); // the default is 256 _serial_gps->setRxBufferSize(2048); // the default is 256
#endif #endif
// if the overrides are not dialled in, set them from the board definitions, if they exist
#if defined(GPS_RX_PIN)
if (!config.position.rx_gpio)
config.position.rx_gpio = GPS_RX_PIN;
#endif
#if defined(GPS_TX_PIN)
if (!config.position.tx_gpio)
config.position.tx_gpio = GPS_TX_PIN;
#endif
// ESP32 has a special set of parameters vs other arduino ports // ESP32 has a special set of parameters vs other arduino ports
#if defined(GPS_RX_PIN) && defined(ARCH_ESP32) #if defined(ARCH_ESP32)
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN); if(config.position.rx_gpio)
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, config.position.rx_gpio, config.position.tx_gpio);
#else #else
_serial_gps->begin(GPS_BAUDRATE); _serial_gps->begin(GPS_BAUDRATE);
#endif #endif
@@ -258,21 +270,30 @@ bool GPS::setup()
pinMode(PIN_GPS_EN, OUTPUT); pinMode(PIN_GPS_EN, OUTPUT);
#endif #endif
#ifdef HAS_PMU
if(config.position.gps_enabled){
setGPSPower(true);
}
#endif
#ifdef PIN_GPS_RESET #ifdef PIN_GPS_RESET
digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms
pinMode(PIN_GPS_RESET, OUTPUT); pinMode(PIN_GPS_RESET, OUTPUT);
delay(10); delay(10);
digitalWrite(PIN_GPS_RESET, 0); digitalWrite(PIN_GPS_RESET, 0);
#endif #endif
setAwake(true); // Wake GPS power before doing any init setAwake(true); // Wake GPS power before doing any init
bool ok = setupGPS(); bool ok = setupGPS();
if (ok) { if (ok) {
notifySleepObserver.observe(&notifySleep); notifySleepObserver.observe(&notifySleep);
notifyDeepSleepObserver.observe(&notifyDeepSleep); notifyDeepSleepObserver.observe(&notifyDeepSleep);
notifyGPSSleepObserver.observe(&notifyGPSSleep);
}
if (config.position.gps_enabled==false) {
setAwake(false);
doGPSpowersave(false);
} }
return ok; return ok;
} }
@@ -281,6 +302,7 @@ GPS::~GPS()
// we really should unregister our sleep observer // we really should unregister our sleep observer
notifySleepObserver.unobserve(&notifySleep); notifySleepObserver.unobserve(&notifySleep);
notifyDeepSleepObserver.unobserve(&notifyDeepSleep); notifyDeepSleepObserver.unobserve(&notifyDeepSleep);
notifyGPSSleepObserver.observe(&notifyGPSSleep);
} }
bool GPS::hasLock() bool GPS::hasLock()
@@ -393,7 +415,7 @@ void GPS::publishUpdate()
DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", p.timestamp, hasValidLocation, hasLock()); DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", p.timestamp, hasValidLocation, hasLock());
// Notify any status instances that are observing us // Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), p); const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), isPowerSaving(), p);
newStatus.notifyObservers(&status); newStatus.notifyObservers(&status);
} }
} }
@@ -404,7 +426,7 @@ int32_t GPS::runOnce()
// if we have received valid NMEA claim we are connected // if we have received valid NMEA claim we are connected
setConnected(); setConnected();
} else { } else {
if(gnssModel == GNSS_MODEL_UBLOX){ if((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)){
// reset the GPS on next bootup // reset the GPS on next bootup
if(devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) { if(devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) {
DEBUG_MSG("GPS is not communicating, trying factory reset on next bootup.\n"); DEBUG_MSG("GPS is not communicating, trying factory reset on next bootup.\n");
@@ -506,6 +528,7 @@ int GPS::prepareDeepSleep(void *unused)
DEBUG_MSG("GPS deep sleep!\n"); DEBUG_MSG("GPS deep sleep!\n");
// For deep sleep we also want abandon any lock attempts (because we want minimum power) // For deep sleep we also want abandon any lock attempts (because we want minimum power)
getSleepTime();
setAwake(false); setAwake(false);
return 0; return 0;
@@ -641,6 +664,11 @@ GPS *createGps()
return new_gps; return new_gps;
} }
} }
else{
GPS *new_gps = new NMEAGPS();
new_gps->setup();
return new_gps;
}
return nullptr; return nullptr;
#endif #endif
} }

View File

@@ -49,6 +49,7 @@ class GPS : private concurrency::OSThread
CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep); CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep);
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep); CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
CallbackObserver<GPS, void *> notifyGPSSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
public: public:
/** If !NULL we will use this serial port to construct our GPS */ /** If !NULL we will use this serial port to construct our GPS */
@@ -77,6 +78,8 @@ class GPS : private concurrency::OSThread
/// Return true if we are connected to a GPS /// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; } bool isConnected() const { return hasGPS; }
bool isPowerSaving() const { return !config.position.gps_enabled;}
/** /**
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP * Restart our lock attempt - try to get and broadcast a GPS reading ASAP
* called after the CPU wakes from light-sleep state * called after the CPU wakes from light-sleep state

View File

@@ -109,7 +109,7 @@ bool NMEAGPS::lookForLocation()
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS #ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
fixType = atoi(gsafixtype.value()); // will set to zero if no data fixType = atoi(gsafixtype.value()); // will set to zero if no data
DEBUG_MSG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType); // DEBUG_MSG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
#endif #endif
// check if GPS has an acceptable lock // check if GPS has an acceptable lock
@@ -168,7 +168,7 @@ bool NMEAGPS::lookForLocation()
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS #ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
p.HDOP = reader.hdop.value(); p.HDOP = reader.hdop.value();
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value()); p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
DEBUG_MSG("PDOP=%d, HDOP=%d\n", dop, reader.hdop.value()); // DEBUG_MSG("PDOP=%d, HDOP=%d\n", p.PDOP, p.HDOP);
#else #else
// FIXME! naive PDOP emulation (assumes VDOP==HDOP) // FIXME! naive PDOP emulation (assumes VDOP==HDOP)
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2) // correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)

View File

@@ -1,4 +1,5 @@
#include "NMEAWPL.h" #include "NMEAWPL.h"
#include "GeoCoord.h"
/* ------------------------------------------- /* -------------------------------------------
* 1 2 3 4 5 6 * 1 2 3 4 5 6
@@ -17,7 +18,15 @@
uint32_t printWPL(char *buf, const Position &pos, const char *name) uint32_t printWPL(char *buf, const Position &pos, const char *name)
{ {
uint32_t len = sprintf(buf, "$GNWPL,%07.2f,%c,%08.2f,%c,%s", pos.latitude_i * 1e-5, pos.latitude_i < 0 ? 'S' : 'N', pos.longitude_i * 1e-5, pos.longitude_i < 0 ? 'W' : 'E', name); GeoCoord geoCoord(pos.latitude_i,pos.longitude_i,pos.altitude);
uint32_t len = sprintf(buf, "$GNWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s",
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; uint32_t chk = 0;
for (uint32_t i = 1; i < len; i++) { for (uint32_t i = 1; i < len; i++) {
chk ^= buf[i]; chk ^= buf[i];
@@ -52,15 +61,20 @@ uint32_t printWPL(char *buf, const Position &pos, const char *name)
uint32_t printGGA(char *buf, const Position &pos) uint32_t printGGA(char *buf, const Position &pos)
{ {
uint32_t len = sprintf(buf, "$GNGGA,%06u.%03u,%07.2f,%c,%08.2f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d", GeoCoord geoCoord(pos.latitude_i,pos.longitude_i,pos.altitude);
uint32_t len = sprintf(buf, "$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,
pos.time % 1000, pos.time % 1000,
pos.latitude_i * 1e-5, pos.latitude_i < 0 ? 'S' : 'N', geoCoord.getDMSLatDeg(),
pos.longitude_i * 1e-5, pos.longitude_i < 0 ? 'W' : 'E', (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.fix_type,
pos.sats_in_view, pos.sats_in_view,
pos.HDOP, pos.HDOP,
pos.altitude, geoCoord.getAltitude(),
'M', 'M',
pos.altitude_geoidal_separation, pos.altitude_geoidal_separation,
'M', 'M',
@@ -73,4 +87,4 @@ uint32_t printGGA(char *buf, const Position &pos)
} }
len += sprintf(buf + len, "*%02X\r\n", chk); len += sprintf(buf + len, "*%02X\r\n", chk);
return len; return len;
} }

View File

@@ -44,7 +44,11 @@ void readFromRTC()
if(rtc_found == PCF8563_RTC) { if(rtc_found == PCF8563_RTC) {
uint32_t now = millis(); uint32_t now = millis();
PCF8563_Class rtc; PCF8563_Class rtc;
#ifdef RTC_USE_WIRE1
rtc.begin(Wire1);
#else
rtc.begin(); rtc.begin();
#endif
auto tc = rtc.getDateTime(); auto tc = rtc.getDateTime();
tm t; tm t;
t.tm_year = tc.year - 1900; t.tm_year = tc.year - 1900;
@@ -110,7 +114,11 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
#elif defined(PCF8563_RTC) #elif defined(PCF8563_RTC)
if(rtc_found == PCF8563_RTC) { if(rtc_found == PCF8563_RTC) {
PCF8563_Class rtc; PCF8563_Class rtc;
rtc.begin(); #ifdef RTC_USE_WIRE1
rtc.begin(Wire1);
#else
rtc.begin();
#endif
tm *t = localtime(&tv->tv_sec); tm *t = localtime(&tv->tv_sec);
rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
DEBUG_MSG("PCF8563_RTC setDateTime %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); DEBUG_MSG("PCF8563_RTC setDateTime %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);

View File

@@ -35,6 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "mesh/Channels.h" #include "mesh/Channels.h"
#include "mesh/generated/deviceonly.pb.h" #include "mesh/generated/deviceonly.pb.h"
#include "modules/TextMessageModule.h" #include "modules/TextMessageModule.h"
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
#include "utils.h" #include "utils.h"
@@ -42,6 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/http/WiFiAPClient.h"
#include "modules/esp32/StoreForwardModule.h"
#endif #endif
#ifdef OLED_RU #ifdef OLED_RU
@@ -95,17 +97,17 @@ static uint16_t displayWidth, displayHeight;
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) #if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
// The screen is bigger so use bigger fonts // The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16 #define FONT_SMALL ArialMT_Plain_16 // Height: 19
#define FONT_MEDIUM ArialMT_Plain_24 #define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24 // Height: 28
#else #else
#ifdef OLED_RU #ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU #define FONT_SMALL ArialMT_Plain_10_RU
#else #else
#define FONT_SMALL ArialMT_Plain_10 #define FONT_SMALL ArialMT_Plain_10 // Height: 13
#endif #endif
#define FONT_MEDIUM ArialMT_Plain_16 #define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24 // Height: 28
#endif #endif
#define fontHeight(font) ((font)[1] + 1) // height is position 1 #define fontHeight(font) ((font)[1] + 1) // height is position 1
@@ -283,27 +285,27 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) 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;
display->setTextAlignment(TEXT_ALIGN_CENTER); display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM); display->setFont(FONT_MEDIUM);
display->drawString(64 + x, y, "Bluetooth"); display->drawString(x_offset + x, y_offset + y, "Bluetooth");
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Enter this code"); y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM -4 : y_offset + FONT_HEIGHT_MEDIUM + 5;
display->drawString(x_offset + x, y_offset + y, "Enter this code");
display->setFont(FONT_LARGE); display->setFont(FONT_LARGE);
String displayPin(btPIN);
String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6);
y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5;
display->drawString(x_offset + x, y_offset + y, pin);
auto displayPin = new String(btPIN);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(12 + x, 26 + y, displayPin->substring(0, 3));
display->drawString(72 + x, 26 + y, displayPin->substring(3, 6));
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
char buf[30]; String deviceName = "Name: ";
const char *name = "Name: "; deviceName.concat(getDeviceName());
strcpy(buf, name); y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5;
strcat(buf, getDeviceName()); display->drawString(x_offset + x, y_offset + y, deviceName);
display->drawString(64 + x, 48 + y, buf);
} }
static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
@@ -329,11 +331,8 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
display->drawString(64 + x, y, "Updating"); display->drawString(64 + x, y, "Updating");
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
if ((millis() / 1000) % 2) { display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ."); display->drawStringMaxWidth(0 + x, 2 + y + FONT_HEIGHT_SMALL *2, x + display->getWidth(), "Please be patient and do not power off.");
} else {
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
}
} }
/// Draw the last text message we received /// Draw the last text message we received
@@ -364,6 +363,9 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
{ {
displayedNodeNum = 0; // Not currently showing a node pane 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];
MeshPacket &mp = devicestate.rx_text_message; MeshPacket &mp = devicestate.rx_text_message;
NodeInfo *node = nodeDB.getNode(getFrom(&mp)); NodeInfo *node = nodeDB.getNode(getFrom(&mp));
// DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from, // DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from,
@@ -373,16 +375,14 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// with the third parameter you can define the width after which words will // with the third parameter you can define the width after which words will
// be wrapped. Currently only spaces and "-" are allowed for wrapping // be wrapped. Currently only spaces and "-" are allowed for wrapping
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_MEDIUM);
String sender = (node && node->has_user) ? node->user.short_name : "???";
display->drawString(0 + x, 0 + y, sender);
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
// the max length of this buffer is much longer than we can possibly print display->setColor(BLACK);
static char tempBuf[96]; display->drawStringf(0 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.payload.bytes); display->drawStringf(1 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
display->setColor(WHITE);
display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf); snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
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 a series of fields in a column, wrapping to multiple colums if needed
@@ -395,6 +395,10 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
int xo = x, yo = y; int xo = x, yo = y;
while (*f) { while (*f) {
display->drawString(xo, yo, *f); display->drawString(xo, yo, *f);
if (display->getColor() == BLACK)
display->drawString(xo + 1, yo, *f);
display->setColor(WHITE);
yo += FONT_HEIGHT_SMALL; yo += FONT_HEIGHT_SMALL;
if (yo > SCREEN_HEIGHT - FONT_HEIGHT_SMALL) { if (yo > SCREEN_HEIGHT - FONT_HEIGHT_SMALL) {
xo += SCREEN_WIDTH / 2; xo += SCREEN_WIDTH / 2;
@@ -463,8 +467,13 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
{ {
char usersString[20]; char usersString[20];
sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal()); sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x, y + 3, 8, 8, imgUser);
#else
display->drawFastImage(x, y, 8, 8, imgUser); display->drawFastImage(x, y, 8, 8, imgUser);
#endif
display->drawString(x + 10, y - 2, usersString); display->drawString(x + 10, y - 2, usersString);
display->drawString(x + 11, y - 2, usersString);
} }
// Draw GPS status summary // Draw GPS status summary
@@ -473,15 +482,18 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
if (config.position.fixed_position) { if (config.position.fixed_position) {
// GPS coordinates are currently fixed // GPS coordinates are currently fixed
display->drawString(x - 1, y - 2, "Fixed GPS"); display->drawString(x - 1, y - 2, "Fixed GPS");
display->drawString(x, y - 2, "Fixed GPS");
return; return;
} }
if (!gps->getIsConnected()) { if (!gps->getIsConnected()) {
display->drawString(x, y - 2, "No GPS"); display->drawString(x, y - 2, "No GPS");
display->drawString(x + 1, y - 2, "No GPS");
return; return;
} }
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty); display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
if (!gps->getHasLock()) { if (!gps->getHasLock()) {
display->drawString(x + 8, y - 2, "No sats"); display->drawString(x + 8, y - 2, "No sats");
display->drawString(x + 9, y - 2, "No sats");
return; return;
} else { } else {
char satsString[3]; char satsString[3];
@@ -506,6 +518,23 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
} }
} }
//Draw status when gps is disabled by PMU
static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{
#ifdef HAS_PMU
String displayLine = "GPS disabled";
int16_t xPos = display->getStringWidth(displayLine);
if (!config.position.gps_enabled){
display->drawString(x + xPos, y, displayLine);
#ifdef GPS_POWER_TOGGLE
display->drawString(x + xPos, y - 2 + FONT_HEIGHT_SMALL, " by button");
#endif
//display->drawString(x + xPos, y + 2, displayLine);
}
#endif
}
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{ {
String displayLine = ""; String displayLine = "";
@@ -538,9 +567,10 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine); display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} else { } else {
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
if (gpsFormat != Config_DisplayConfig_GpsCoordinateFormat_DMS) { if (gpsFormat != Config_DisplayConfig_GpsCoordinateFormat_DMS) {
char coordinateLine[22]; char coordinateLine[22];
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_DEC) { // Decimal Degrees if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_DEC) { // Decimal Degrees
sprintf(coordinateLine, "%f %f", geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7); sprintf(coordinateLine, "%f %f", geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7);
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_UTM) { // Universal Transverse Mercator } else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_UTM) { // Universal Transverse Mercator
@@ -668,16 +698,16 @@ static uint16_t getCompassDiam(OLEDDisplay *display)
{ {
uint16_t diam = 0; uint16_t diam = 0;
// get the smaller of the 2 dimensions and subtract 20 // get the smaller of the 2 dimensions and subtract 20
if(display->getWidth() > display->getHeight()) { if(display->getWidth() > (display->getHeight() - FONT_HEIGHT_SMALL)) {
diam = display->getHeight(); diam = display->getHeight() - FONT_HEIGHT_SMALL;
// if 2/3 of the other size would be smaller, use that // if 2/3 of the other size would be smaller, use that
if (diam > (display->getWidth() * 2 / 3)) { if (diam > (display->getWidth() * 2 / 3)) {
diam = display->getWidth() * 2 / 3; diam = display->getWidth() * 2 / 3;
} }
} else { } else {
diam = display->getWidth(); diam = display->getWidth();
if (diam > (display->getHeight() * 2 / 3)) { if (diam > ((display->getHeight() - FONT_HEIGHT_SMALL) * 2 / 3)) {
diam = display->getHeight() * 2 / 3; diam = (display->getHeight() - FONT_HEIGHT_SMALL) * 2 / 3;
} }
} }
@@ -757,6 +787,8 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
const char *username = node->has_user ? node->user.long_name : "Unknown Name"; const char *username = node->has_user ? node->user.long_name : "Unknown Name";
static char signalStr[20]; static char signalStr[20];
@@ -787,7 +819,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
const char *fields[] = {username, distStr, signalStr, lastStr, NULL}; const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
// coordinates for the center of the compass/circle // coordinates for the center of the compass/circle
int16_t compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5, compassY = y + SCREEN_HEIGHT / 2; int16_t compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5, compassY = y + FONT_HEIGHT_SMALL + (SCREEN_HEIGHT - FONT_HEIGHT_SMALL) / 2;
bool hasNodeHeading = false; bool hasNodeHeading = false;
if (ourNode && hasPosition(ourNode)) { if (ourNode && hasPosition(ourNode)) {
@@ -830,33 +862,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); display->drawCircle(compassX, compassY, getCompassDiam(display) / 2);
display->setColor(BLACK);
// Must be after distStr is populated // Must be after distStr is populated
drawColumns(display, x, y, fields); drawColumns(display, x, y, fields);
} }
#if 0
void _screen_header()
{
if (!disp)
return;
// Message count
//snprintf(buffer, sizeof(buffer), "#%03d", ttn_get_count() % 1000);
//display->setTextAlignment(TEXT_ALIGN_LEFT);
//display->drawString(0, 2, buffer);
// Datetime
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(display->getWidth()/2, 2, gps.getTimeStr());
// Satellite count
display->setTextAlignment(TEXT_ALIGN_RIGHT);
char buffer[10];
display->drawString(display->getWidth() - SATELLITE_IMAGE_WIDTH - 4, 2, itoa(gps.satellites.value(), buffer, 10));
display->drawXbm(display->getWidth() - SATELLITE_IMAGE_WIDTH, 0, SATELLITE_IMAGE_WIDTH, SATELLITE_IMAGE_HEIGHT, SATELLITE_IMAGE);
}
#endif
// #ifdef RAK4630 // #ifdef RAK4630
// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), // Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl),
// dispdev_oled(address, sda, scl), ui(&dispdev) // dispdev_oled(address, sda, scl), ui(&dispdev)
@@ -1356,6 +1366,9 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
char channelStr[20]; char channelStr[20];
{ {
concurrency::LockGuard guard(&lock); concurrency::LockGuard guard(&lock);
@@ -1365,18 +1378,54 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Display power status // Display power status
if (powerStatus->getHasBattery()) if (powerStatus->getHasBattery())
drawBattery(display, x, y + 2, imgBattery, powerStatus); drawBattery(display, x + 1, y + 3, imgBattery, powerStatus);
else if (powerStatus->knowsUSB()) else if (powerStatus->knowsUSB())
display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower); display->drawFastImage(x + 1, y + 3, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
// Display nodes status // Display nodes status
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus); drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus);
// Display GPS status // Display GPS status
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus); if (!config.position.gps_enabled){
int16_t yPos = y + 2;
#ifdef GPS_POWER_TOGGLE
yPos = (y + 10 + FONT_HEIGHT_SMALL);
#endif
drawGPSpowerstat(display, x, yPos, gpsStatus);
} else {
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus);
}
display->setColor(WHITE);
// Draw the channel name // Draw the channel name
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr); display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
// Draw our hardware ID to assist with bluetooth pairing // Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo); if (moduleConfig.store_forward.enabled) {
#if 0
if (millis() - storeForwardModule->lastHeartbeat > (storeForwardModule->heartbeatInterval * 1200)) { //no heartbeat, overlap a bit
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_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, imgQuestionL2);
#else
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgQuestion);
#endif
} else {
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_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, imgSFL2);
#else
display->drawFastImage(x + SCREEN_WIDTH - 13 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 11, 8, imgSF);
#endif
}
#endif
} else {
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_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, imgInfoL2);
#else
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo);
#endif
}
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId);
// Draw any log messages // Draw any log messages
@@ -1403,15 +1452,24 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
if (WiFi.status() != WL_CONNECTED) { if (WiFi.status() != WL_CONNECTED) {
display->drawString(x, y, String("WiFi: Not Connected")); display->drawString(x, y, String("WiFi: Not Connected"));
display->drawString(x + 1, y, String("WiFi: Not Connected"));
} else { } else {
display->drawString(x, y, String("WiFi: Connected")); display->drawString(x, y, String("WiFi: Connected"));
display->drawString(x + 1, y, String("WiFi: Connected"));
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())), y, display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())), y,
"RSSI " + String(WiFi.RSSI())); "RSSI " + String(WiFi.RSSI()));
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())) - 1, y,
"RSSI " + String(WiFi.RSSI()));
} }
display->setColor(WHITE);
/* /*
- WL_CONNECTED: assigned when connected to a WiFi network; - WL_CONNECTED: assigned when connected to a WiFi network;
- WL_NO_SSID_AVAIL: assigned when no SSID are available; - WL_NO_SSID_AVAIL: assigned when no SSID are available;
@@ -1520,6 +1578,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
char batStr[20]; char batStr[20];
if (powerStatus->getHasBattery()) { if (powerStatus->getHasBattery()) {
int batV = powerStatus->getBatteryVoltageMv() / 1000; int batV = powerStatus->getBatteryVoltageMv() / 1000;
@@ -1530,9 +1591,11 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// Line 1 // Line 1
display->drawString(x, y, batStr); display->drawString(x, y, batStr);
display->drawString(x + 1, y, batStr);
} else { } else {
// Line 1 // Line 1
display->drawString(x, y, String("USB")); display->drawString(x, y, String("USB"));
display->drawString(x + 1, y, String("USB"));
} }
auto mode = ""; auto mode = "";
@@ -1565,6 +1628,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
} }
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
// Line 2 // Line 2
uint32_t currentMillis = millis(); uint32_t currentMillis = millis();
@@ -1577,6 +1641,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// minutes %= 60; // minutes %= 60;
// hours %= 24; // hours %= 24;
display->setColor(WHITE);
// Show uptime as days, hours, minutes OR seconds // Show uptime as days, hours, minutes OR seconds
String uptime; String uptime;
if (days >= 2) if (days >= 2)
@@ -1612,7 +1678,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
char chUtil[13]; char chUtil[13];
sprintf(chUtil, "ChUtil %2.0f%%", airTime->channelUtilizationPercent()); sprintf(chUtil, "ChUtil %2.0f%%", airTime->channelUtilizationPercent());
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
if (config.position.gps_enabled) {
// Line 3 // Line 3
if (config.display.gps_format != if (config.display.gps_format !=
Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
@@ -1620,7 +1686,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// Line 4 // Line 4
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus); drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
} else {
drawGPSpowerstat(display, x - (SCREEN_WIDTH / 4), y + FONT_HEIGHT_SMALL * 2, gpsStatus);
}
/* Display a heartbeat pixel that blinks every time the frame is redrawn */ /* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
if (heartbeat) if (heartbeat)

View File

@@ -21,6 +21,7 @@ class Screen
void startBluetoothPinScreen(uint32_t pin) {} void startBluetoothPinScreen(uint32_t pin) {}
void stopBluetoothPinScreen() {} void stopBluetoothPinScreen() {}
void startRebootScreen() {} void startRebootScreen() {}
void startFirmwareUpdateScreen() {}
}; };
} }

View File

@@ -12,36 +12,18 @@ const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08,
const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C }; const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C };
const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF }; const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF };
const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF }; const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF };
const uint8_t imgInfo[] PROGMEM = { 0xFF, 0x81, 0x81, 0xB5, 0xB5, 0x81, 0x81, 0xFF };
#include "img/icon.xbm" #if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
const uint8_t imgQuestionL1[] PROGMEM = { 0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff };
// We now programmatically draw our compass const uint8_t imgQuestionL2[] PROGMEM = { 0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f };
#if 0 const uint8_t imgInfoL1[] PROGMEM = { 0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff };
const const uint8_t imgInfoL2[] PROGMEM = { 0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f };
#include "img/compass.xbm" const uint8_t imgSFL1[] PROGMEM = { 0xb6, 0x8f, 0x19, 0x11, 0x31, 0xe3, 0xc2, 0x01, 0x01, 0xf9, 0xf9, 0x89, 0x89, 0x89, 0x09, 0xeb};
const uint8_t imgSFL2[] PROGMEM = { 0x0e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x00, 0x0f, 0x0f, 0x00, 0x08, 0x08, 0x08, 0x0f};
#else
const uint8_t imgInfo[] PROGMEM = { 0xff, 0x81, 0x00, 0xfb, 0xfb, 0x00, 0x81, 0xff };
const uint8_t imgQuestion[] PROGMEM = { 0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1, 0xdf };
const uint8_t imgSF[] PROGMEM = { 0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5};
#endif #endif
#if 0 #include "img/icon.xbm"
const uint8_t activeSymbol[] PROGMEM = {
B00000000,
B00000000,
B00011000,
B00100100,
B01000010,
B01000010,
B00100100,
B00011000
};
const uint8_t inactiveSymbol[] PROGMEM = {
B00000000,
B00000000,
B00000000,
B00000000,
B00011000,
B00011000,
B00000000,
B00000000
};
#endif

View File

@@ -1,28 +0,0 @@
#define compass_width 48
#define compass_height 48
static char compass_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00,
0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00,
0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00,
0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00,
0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01,
0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01,
0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F,
0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F,
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03,
0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03,
0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01, 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01,
0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00,
0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00,
0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00,
0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00,
0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

View File

@@ -1,6 +0,0 @@
#define pin_width 13
#define pin_height 13
static char pin_bits[] = {
0x00, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xBC, 0x07, 0xBC, 0x07,
0xFC, 0x07, 0xF8, 0x03, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0xE0, 0x00,
0x00, 0x00, };

View File

@@ -8,8 +8,6 @@
#include "configuration.h" #include "configuration.h"
#include "error.h" #include "error.h"
#include "power.h" #include "power.h"
// #include "rom/rtc.h"
//#include "DSRRouter.h"
#include "ReliableRouter.h" #include "ReliableRouter.h"
// #include "debug.h" // #include "debug.h"
#include "FSCommon.h" #include "FSCommon.h"
@@ -87,8 +85,6 @@ uint8_t kb_model;
// The I2C address of the RTC Module (if found) // The I2C address of the RTC Module (if found)
uint8_t rtc_found; uint8_t rtc_found;
bool rIf_wide_lora = false;
// Keystore Chips // Keystore Chips
uint8_t keystore_found; uint8_t keystore_found;
#ifndef ARCH_PORTDUINO #ifndef ARCH_PORTDUINO
@@ -102,7 +98,7 @@ uint32_t serialSinceMsec;
bool pmu_found; bool pmu_found;
// Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan // Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan
uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t nodeTelemetrySensorsMap[_TelemetrySensorType_MAX + 1] = { 0 }; // one is enough, missing elements will be initialized to 0 anyway.
Router *router = NULL; // Users of router don't care what sort of subclass implements that API Router *router = NULL; // Users of router don't care what sort of subclass implements that API
@@ -142,8 +138,9 @@ bool ButtonThread::shutdown_on_long_stop = false;
#endif #endif
static Periodic *ledPeriodic; static Periodic *ledPeriodic;
static OSThread *powerFSMthread, *buttonThread; static OSThread *powerFSMthread;
#if HAS_BUTTON #if HAS_BUTTON
static OSThread *buttonThread;
uint32_t ButtonThread::longPressTime = 0; uint32_t ButtonThread::longPressTime = 0;
#endif #endif
@@ -218,7 +215,6 @@ void setup()
fsInit(); fsInit();
// router = new DSRRouter();
router = new ReliableRouter(); router = new ReliableRouter();
#ifdef I2C_SDA1 #ifdef I2C_SDA1
@@ -246,8 +242,32 @@ void setup()
digitalWrite(PIN_3V3_EN, 1); digitalWrite(PIN_3V3_EN, 1);
#endif #endif
// Currently only the tbeam has a PMU
// PMU initialization needs to be placed before scanI2Cdevice
power = new Power();
power->setStatusHandler(powerStatus);
powerStatus->observe(&power->newStatus);
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
#ifdef LILYGO_TBEAM_S3_CORE
// In T-Beam-S3-core, the I2C device cannot be scanned before power initialization, otherwise the device will be stuck
// PCF8563 RTC in tbeam-s3 uses Wire1 to share I2C bus
Wire1.beginTransmission(PCF8563_RTC);
if (Wire1.endTransmission() == 0){
rtc_found = PCF8563_RTC;
DEBUG_MSG("PCF8563 RTC found\n");
}
#endif
// We need to scan here to decide if we have a screen for nodeDB.init() // We need to scan here to decide if we have a screen for nodeDB.init()
scanI2Cdevice(); scanI2Cdevice();
#ifdef HAS_SDCARD
setupSDCard();
#endif
#ifdef RAK4630 #ifdef RAK4630
// scanEInkDevice(); // scanEInkDevice();
#endif #endif
@@ -282,22 +302,10 @@ void setup()
playStartMelody(); playStartMelody();
// Currently only the tbeam has a PMU
power = new Power();
power->setStatusHandler(powerStatus);
powerStatus->observe(&power->newStatus);
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
/*
* Repeat the scanning for I2C devices after power initialization or look for 'latecomers'.
* Boards with an PMU need to be powered on to correctly scan to the device address, such as t-beam-s3-core
*/
scanI2Cdevice();
// fixed screen override? // fixed screen override?
if (config.display.oled != Config_DisplayConfig_OledType_OLED_AUTO) if (config.display.oled != Config_DisplayConfig_OledType_OLED_AUTO)
screen_model = config.display.oled; screen_model = config.display.oled;
// Init our SPI controller (must be before screen and lora) // Init our SPI controller (must be before screen and lora)
initSPI(); initSPI();
#ifndef ARCH_ESP32 #ifndef ARCH_ESP32
@@ -376,7 +384,7 @@ void setup()
} }
#endif #endif
#if defined(USE_SX1280) && !defined(ARCH_PORTDUINO) #if defined(USE_SX1280)
if (!rIf) { if (!rIf) {
rIf = new SX1280Interface(SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY, SPI); rIf = new SX1280Interface(SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY, SPI);
if (!rIf->init()) { if (!rIf->init()) {
@@ -385,7 +393,6 @@ void setup()
rIf = NULL; rIf = NULL;
} else { } else {
DEBUG_MSG("SX1280 Radio init succeeded, using SX1280 radio\n"); DEBUG_MSG("SX1280 Radio init succeeded, using SX1280 radio\n");
rIf_wide_lora = true;
} }
} }
#endif #endif
@@ -442,6 +449,30 @@ void setup()
} }
#endif #endif
// check if the radio chip matches the selected region
if((config.lora.region == Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLora())){
DEBUG_MSG("Warning: Radio chip does not support 2.4GHz LoRa. Reverting to unset.\n");
config.lora.region = Config_LoRaConfig_RegionCode_UNSET;
nodeDB.saveToDisk(SEGMENT_CONFIG);
if(!rIf->reconfigure()) {
DEBUG_MSG("Reconfigure failed, rebooting\n");
screen->startRebootScreen();
rebootAtMsec = millis() + 5000;
}
}
if((config.lora.region != Config_LoRaConfig_RegionCode_LORA_24) && (rIf->wideLora())){
DEBUG_MSG("Warning: Radio chip only supports 2.4GHz LoRa. Adjusting Region.\n");
config.lora.region = Config_LoRaConfig_RegionCode_LORA_24;
nodeDB.saveToDisk(SEGMENT_CONFIG);
if(!rIf->reconfigure()) {
DEBUG_MSG("Reconfigure failed, rebooting\n");
screen->startRebootScreen();
rebootAtMsec = millis() + 5000;
}
}
#if HAS_WIFI || HAS_ETHERNET #if HAS_WIFI || HAS_ETHERNET
mqttInit(); mqttInit();
#endif #endif

View File

@@ -6,7 +6,7 @@
#include "PowerStatus.h" #include "PowerStatus.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "mesh/generated/telemetry.pb.h" #include "mesh/generated/telemetry.pb.h"
#ifndef ARCH_PORTDUINO #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include <SparkFun_ATECCX08a_Arduino_Library.h> #include <SparkFun_ATECCX08a_Arduino_Library.h>
#endif #endif
@@ -17,17 +17,16 @@ extern uint8_t kb_model;
extern uint8_t rtc_found; extern uint8_t rtc_found;
extern uint8_t keystore_found; extern uint8_t keystore_found;
extern bool rIf_wide_lora;
extern bool eink_found; extern bool eink_found;
extern bool pmu_found; extern bool pmu_found;
extern bool isCharging; extern bool isCharging;
extern bool isUSBPowered; extern bool isUSBPowered;
#ifndef ARCH_PORTDUINO #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
extern ATECCX08A atecc; extern ATECCX08A atecc;
#endif #endif
extern uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658+1]; extern uint8_t nodeTelemetrySensorsMap[_TelemetrySensorType_MAX + 1];
extern int TCPPort; // set by Portduino extern int TCPPort; // set by Portduino

View File

@@ -196,6 +196,17 @@ Channel &Channels::getByIndex(ChannelIndex chIndex)
return *ch; return *ch;
} }
Channel &Channels::getByName(const char* chName)
{
for (ChannelIndex i = 0; i < getNumChannels(); i++) {
if (strcasecmp(channelFile.channels[i].settings.name, chName) == 0) {
return channelFile.channels[i];
}
}
return getByIndex(getPrimaryIndex());
}
void Channels::setChannel(const Channel &c) void Channels::setChannel(const Channel &c)
{ {
Channel &old = getByIndex(c.index); Channel &old = getByIndex(c.index);

View File

@@ -40,6 +40,9 @@ class Channels
/** Return the Channel for a specified index */ /** Return the Channel for a specified index */
Channel &getByIndex(ChannelIndex chIndex); Channel &getByIndex(ChannelIndex chIndex);
/** Return the Channel for a specified name, return primary if not found. */
Channel &getByName(const char* chName);
/** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted /** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted
* to be primary, force all other channels to be secondary. * to be primary, force all other channels to be secondary.
*/ */

View File

@@ -41,6 +41,11 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
tosend->hop_limit--; // bump down the hop count tosend->hop_limit--; // bump down the hop count
// If it is a traceRoute request, update the route that it went via me
if (p->which_payload_variant == MeshPacket_decoded_tag && traceRouteModule->wantPacket(p)) {
traceRouteModule->updateRoute(tosend);
}
printPacket("Rebroadcasting received floodmsg to neighbors", p); printPacket("Rebroadcasting received floodmsg to neighbors", p);
// Note: we are careful to resend using the original senders node id // Note: we are careful to resend using the original senders node id
// We are careful not to call our hooked version of send() - because we don't want to check this again // We are careful not to call our hooked version of send() - because we don't want to check this again

View File

@@ -2,6 +2,7 @@
#include "PacketHistory.h" #include "PacketHistory.h"
#include "Router.h" #include "Router.h"
#include "modules/TraceRouteModule.h"
/** /**
* This is a mixin that extends Router with the ability to do Naive Flooding (in the standard mesh protocol sense) * This is a mixin that extends Router with the ability to do Naive Flooding (in the standard mesh protocol sense)

View File

@@ -7,7 +7,4 @@
template class SX126xInterface<SX1262>; template class SX126xInterface<SX1262>;
template class SX126xInterface<SX1268>; template class SX126xInterface<SX1268>;
template class SX126xInterface<LLCC68>; template class SX126xInterface<LLCC68>;
#if !defined(ARCH_PORTDUINO)
template class SX128xInterface<SX1280>; template class SX128xInterface<SX1280>;
#endif

View File

@@ -104,16 +104,17 @@ bool MeshService::reloadConfig(int saveWhat)
} }
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh /// The owner User record just got updated, update our node DB and broadcast the info into the mesh
void MeshService::reloadOwner() void MeshService::reloadOwner(bool shouldSave)
{ {
// DEBUG_MSG("reloadOwner()\n"); // DEBUG_MSG("reloadOwner()\n");
// update our local data directly // update our local data directly
nodeDB.updateUser(nodeDB.getNodeNum(), owner); nodeDB.updateUser(nodeDB.getNodeNum(), owner);
assert(nodeInfoModule); assert(nodeInfoModule);
// update everyone else // update everyone else and save to disk
if (nodeInfoModule) if (nodeInfoModule && shouldSave) {
nodeInfoModule->sendOurNodeInfo(); nodeInfoModule->sendOurNodeInfo();
nodeDB.saveToDisk(SEGMENT_DEVICESTATE); nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
}
} }
/** /**

View File

@@ -69,7 +69,7 @@ class MeshService
bool reloadConfig(int saveWhat=SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS); bool reloadConfig(int saveWhat=SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh /// The owner User record just got updated, update our node DB and broadcast the info into the mesh
void reloadOwner(); void reloadOwner(bool shouldSave = true);
/// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least /// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least
/// sends our owner /// sends our owner

View File

@@ -162,6 +162,7 @@ void NodeDB::installDefaultConfig()
config.has_network = true; config.has_network = true;
config.has_bluetooth = true; config.has_bluetooth = true;
config.lora.tx_enabled = true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off) config.lora.tx_enabled = true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off)
config.lora.override_duty_cycle = false;
config.lora.region = Config_LoRaConfig_RegionCode_UNSET; config.lora.region = Config_LoRaConfig_RegionCode_UNSET;
config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST; config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST;
config.lora.hop_limit = HOP_RELIABLE; config.lora.hop_limit = HOP_RELIABLE;
@@ -204,6 +205,7 @@ void NodeDB::installDefaultModuleConfig()
{ {
DEBUG_MSG("Installing default ModuleConfig\n"); DEBUG_MSG("Installing default ModuleConfig\n");
memset(&moduleConfig, 0, sizeof(ModuleConfig)); memset(&moduleConfig, 0, sizeof(ModuleConfig));
moduleConfig.version = DEVICESTATE_CUR_VER; moduleConfig.version = DEVICESTATE_CUR_VER;
moduleConfig.has_mqtt = true; moduleConfig.has_mqtt = true;
moduleConfig.has_range_test = true; moduleConfig.has_range_test = true;
@@ -213,6 +215,10 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.has_external_notification = true; moduleConfig.has_external_notification = true;
moduleConfig.has_canned_message = true; moduleConfig.has_canned_message = true;
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(moduleConfig.mqtt.address));
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password));
initModuleConfigIntervals(); initModuleConfigIntervals();
} }
@@ -470,6 +476,15 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_
DEBUG_MSG("Error: can't rename new pref file\n"); DEBUG_MSG("Error: can't rename new pref file\n");
} else { } else {
DEBUG_MSG("Can't write prefs\n"); DEBUG_MSG("Can't write prefs\n");
#ifdef ARCH_NRF52
static uint8_t failedCounter = 0;
failedCounter++;
if(failedCounter >= 2){
FSCom.format();
//After formatting, the device needs to be restarted
nodeDB.resetRadioConfig(true);
}
#endif
} }
#else #else
DEBUG_MSG("ERROR: Filesystem not implemented\n"); DEBUG_MSG("ERROR: Filesystem not implemented\n");
@@ -741,9 +756,9 @@ void recordCriticalError(CriticalErrorCode code, uint32_t address, const char *f
String lcd = String("Critical error ") + code + "!\n"; String lcd = String("Critical error ") + code + "!\n";
screen->print(lcd.c_str()); screen->print(lcd.c_str());
if (filename) if (filename)
DEBUG_MSG("NOTE! Recording critical error %d at %s:%lx\n", code, filename, address); DEBUG_MSG("NOTE! Recording critical error %d at %s:%lu\n", code, filename, address);
else else
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address); DEBUG_MSG("NOTE! Recording critical error %d, address=0x%lx\n", code, address);
// Record error to DB // Record error to DB
myNodeInfo.error_code = code; myNodeInfo.error_code = code;

View File

@@ -58,7 +58,7 @@ class NodeDB
void init(); void init();
/// write to flash /// write to flash
void saveToDisk(int saveWhat=SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS), saveChannelsToDisk(), saveDeviceStateToDisk(); void saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS), saveChannelsToDisk(), saveDeviceStateToDisk();
/** Reinit radio config if needed, because either: /** Reinit radio config if needed, because either:
* a) sometimes a buggy android app might send us bogus settings or * a) sometimes a buggy android app might send us bogus settings or
@@ -194,6 +194,10 @@ extern NodeDB nodeDB;
#define default_min_wake_secs 10 #define default_min_wake_secs 10
#define default_screen_on_secs 60 * 10 #define default_screen_on_secs 60 * 10
#define default_mqtt_address "mqtt.meshtastic.org"
#define default_mqtt_username "meshdev"
#define default_mqtt_password "large4cats"
inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval) inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval)
{ {
if (configuredInterval > 0) return configuredInterval * 1000; if (configuredInterval > 0) return configuredInterval * 1000;

View File

@@ -129,6 +129,7 @@ bool RF95Interface::reconfigure()
if (power > MAX_POWER) // This chip has lower power limits than some if (power > MAX_POWER) // This chip has lower power limits than some
power = MAX_POWER; power = MAX_POWER;
err = lora->setOutputPower(power); err = lora->setOutputPower(power);
if (err != RADIOLIB_ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING); RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);

View File

@@ -89,7 +89,7 @@ const RegionInfo regions[] = {
https://rrf.rsm.govt.nz/smart-web/smart/page/-smart/domain/licence/LicenceSummary.wdk?id=219752 https://rrf.rsm.govt.nz/smart-web/smart/page/-smart/domain/licence/LicenceSummary.wdk?id=219752
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
*/ */
RDEF(NZ_865, 864.0f, 868.0f, 100, 0, 0, true, false, false), RDEF(NZ_865, 864.0f, 868.0f, 100, 0, 36, true, false, false),
/* /*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
@@ -177,7 +177,7 @@ uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
static uint8_t bytes[MAX_RHPACKETLEN]; static uint8_t bytes[MAX_RHPACKETLEN];
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded); size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader)); uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader));
// Make sure enough time has elapsed for this packet to be sent and an ACK is received. // Make sure enough time has elapsed for this packet to be sent and an ACK is received.
// DEBUG_MSG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec); // DEBUG_MSG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec);
float channelUtil = airTime->channelUtilizationPercent(); float channelUtil = airTime->channelUtilizationPercent();
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax); uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
@@ -189,7 +189,7 @@ uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
uint32_t RadioInterface::getTxDelayMsec() uint32_t RadioInterface::getTxDelayMsec()
{ {
/** We wait a random multiple of 'slotTimes' (see definition in header file) in order to avoid collisions. /** We wait a random multiple of 'slotTimes' (see definition in header file) in order to avoid collisions.
The pool to take a random multiple from is the contention window (CW), which size depends on the The pool to take a random multiple from is the contention window (CW), which size depends on the
current channel utilization. */ current channel utilization. */
float channelUtil = airTime->channelUtilizationPercent(); float channelUtil = airTime->channelUtilizationPercent();
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax); uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
@@ -225,7 +225,7 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr)
void printPacket(const char *prefix, const MeshPacket *p) void printPacket(const char *prefix, const MeshPacket *p)
{ {
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff, DEBUG_MSG("%s (id=0x%08x fr=0x%02x to=0x%02x, WantAck=%d, HopLim=%d Ch=0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff,
p->want_ack, p->hop_limit, p->channel); p->want_ack, p->hop_limit, p->channel);
if (p->which_payload_variant == MeshPacket_decoded_tag) { if (p->which_payload_variant == MeshPacket_decoded_tag) {
auto &s = p->decoded; auto &s = p->decoded;
@@ -365,37 +365,37 @@ void RadioInterface::applyModemConfig()
switch (loraConfig.modem_preset) { switch (loraConfig.modem_preset) {
case Config_LoRaConfig_ModemPreset_SHORT_FAST: case Config_LoRaConfig_ModemPreset_SHORT_FAST:
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 8;
sf = 7; sf = 7;
break; break;
case Config_LoRaConfig_ModemPreset_SHORT_SLOW: case Config_LoRaConfig_ModemPreset_SHORT_SLOW:
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 8;
sf = 8; sf = 8;
break; break;
case Config_LoRaConfig_ModemPreset_MEDIUM_FAST: case Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 8;
sf = 9; sf = 9;
break; break;
case Config_LoRaConfig_ModemPreset_MEDIUM_SLOW: case Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 8;
sf = 10; sf = 10;
break; break;
case Config_LoRaConfig_ModemPreset_LONG_FAST: case Config_LoRaConfig_ModemPreset_LONG_FAST:
bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250; bw = (myRegion->wideLora) ? 812.5 : 250;
cr = 8; cr = 8;
sf = 11; sf = 11;
break; break;
case Config_LoRaConfig_ModemPreset_LONG_SLOW: case Config_LoRaConfig_ModemPreset_LONG_SLOW:
bw = (myRegion->wideLora && rIf_wide_lora) ? 400 : 125; bw = (myRegion->wideLora) ? 406.25 : 125;
cr = 8; cr = 8;
sf = 12; sf = 12;
break; break;
case Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW: case Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
bw = (myRegion->wideLora && rIf_wide_lora) ? 200 : 31.25; bw = (myRegion->wideLora) ? 203.125 : 31.25;
cr = 8; cr = 8;
sf = 12; sf = 12;
break; break;
@@ -411,6 +411,14 @@ void RadioInterface::applyModemConfig()
bw = 31.25; bw = 31.25;
if (bw == 62) // Fix for 62.5Khz bandwidth if (bw == 62) // Fix for 62.5Khz bandwidth
bw = 62.5; bw = 62.5;
if (bw == 200)
bw = 203.125;
if (bw == 400)
bw = 406.25;
if (bw == 800)
bw = 812.5;
if (bw == 1600)
bw = 1625.0;
} }
power = loraConfig.tx_power; power = loraConfig.tx_power;
@@ -424,7 +432,7 @@ void RadioInterface::applyModemConfig()
// Set final tx_power back onto config // Set final tx_power back onto config
loraConfig.tx_power = (int8_t)power; // cppcheck-suppress assignmentAddressToInteger loraConfig.tx_power = (int8_t)power; // cppcheck-suppress assignmentAddressToInteger
// Calculate the number of channels // Calculate the number of channels
uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000))); uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000)));
@@ -441,9 +449,10 @@ void RadioInterface::applyModemConfig()
saveChannelNum(channel_num); saveChannelNum(channel_num);
saveFreq(freq + config.lora.frequency_offset); saveFreq(freq + config.lora.frequency_offset);
DEBUG_MSG("Radio freq=%.3f, config.lora.frequency_offset=%.3f\n", freq, config.lora.frequency_offset);
DEBUG_MSG("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power); DEBUG_MSG("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power);
DEBUG_MSG("Radio myRegion->freqStart / myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart); DEBUG_MSG("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart);
DEBUG_MSG("Radio myRegion->numChannels: %d\n", numChannels); DEBUG_MSG("Radio myRegion->numChannels: %d x %.3fkHz\n", numChannels, bw);
DEBUG_MSG("Radio channel_num: %d\n", channel_num); DEBUG_MSG("Radio channel_num: %d\n", channel_num);
DEBUG_MSG("Radio frequency: %f\n", getFreq()); DEBUG_MSG("Radio frequency: %f\n", getFreq());
DEBUG_MSG("Slot time: %u msec\n", slotTimeMsec); DEBUG_MSG("Slot time: %u msec\n", slotTimeMsec);

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include "../concurrency/NotifiedWorkerThread.h"
#include "MemoryPool.h" #include "MemoryPool.h"
#include "MeshTypes.h" #include "MeshTypes.h"
#include "Observer.h" #include "Observer.h"
@@ -97,6 +96,8 @@ class RadioInterface
*/ */
virtual bool canSleep() { return true; } virtual bool canSleep() { return true; }
virtual bool wideLora() { return false; }
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep. /// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
virtual bool sleep() { return true; } virtual bool sleep() { return true; }

View File

@@ -3,6 +3,7 @@
#include "NodeDB.h" #include "NodeDB.h"
#include "SPILock.h" #include "SPILock.h"
#include "configuration.h" #include "configuration.h"
#include "main.h"
#include "error.h" #include "error.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include <pb_decode.h> #include <pb_decode.h>
@@ -11,17 +12,6 @@
// FIXME, we default to 4MHz SPI, SPI mode 0, check if the datasheet says it can really do that // FIXME, we default to 4MHz SPI, SPI mode 0, check if the datasheet says it can really do that
static SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0); static SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
#ifdef ARCH_PORTDUINO
void LockingModule::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes)
{
concurrency::LockGuard g(spiLock);
Module::SPItransfer(cmd, reg, dataOut, dataIn, numBytes);
}
#else
void LockingModule::SPIbeginTransaction() void LockingModule::SPIbeginTransaction()
{ {
spiLock->lock(); spiLock->lock();
@@ -36,8 +26,6 @@ void LockingModule::SPIendTransaction()
Module::SPIendTransaction(); Module::SPIendTransaction();
} }
#endif
RadioLibInterface::RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, RadioLibInterface::RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
SPIClass &spi, PhysicalLayer *_iface) SPIClass &spi, PhysicalLayer *_iface)
: NotifiedWorkerThread("RadioIf"), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface) : NotifiedWorkerThread("RadioIf"), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface)
@@ -100,10 +88,8 @@ bool RadioLibInterface::canSendImmediately()
if (busyTx && (millis() - lastTxStart > 60000)) { if (busyTx && (millis() - lastTxStart > 60000)) {
DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n"); DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
RECORD_CRITICALERROR(CriticalErrorCode_TRANSMIT_FAILED); RECORD_CRITICALERROR(CriticalErrorCode_TRANSMIT_FAILED);
#ifdef ARCH_ESP32 // reboot in 5 seconds when this condition occurs.
if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot rebootAtMsec = lastTxStart + 65000;
ESP.restart();
#endif
} }
if (busyRx) if (busyRx)
DEBUG_MSG("Can not send yet, busyRx\n"); DEBUG_MSG("Can not send yet, busyRx\n");
@@ -399,6 +385,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
int res = iface->startTransmit(radiobuf, numbytes); int res = iface->startTransmit(radiobuf, numbytes);
if (res != RADIOLIB_ERR_NONE) { if (res != RADIOLIB_ERR_NONE) {
DEBUG_MSG("startTransmit failed, error=%d\n", res);
RECORD_CRITICALERROR(CriticalErrorCode_RADIO_SPI_BUG); RECORD_CRITICALERROR(CriticalErrorCode_RADIO_SPI_BUG);
// This send failed, but make sure to 'complete' it properly // This send failed, but make sure to 'complete' it properly

View File

@@ -1,10 +1,9 @@
#pragma once #pragma once
#include "../concurrency/OSThread.h" #include "concurrency/NotifiedWorkerThread.h"
#include "RadioInterface.h" #include "RadioInterface.h"
#include "MeshPacketQueue.h" #include "MeshPacketQueue.h"
#define RADIOLIB_EXCLUDE_HTTP
#include <RadioLib.h> #include <RadioLib.h>
// ESP32 has special rules about ISR code // ESP32 has special rules about ISR code
@@ -41,12 +40,8 @@ class LockingModule : public Module
{ {
} }
#ifdef ARCH_PORTDUINO
void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes) override;
#else
void SPIbeginTransaction() override; void SPIbeginTransaction() override;
void SPIendTransaction() override; void SPIendTransaction() override;
#endif
}; };
class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread

View File

@@ -90,13 +90,16 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
{ {
NodeNum ourNode = getNodeNum(); NodeNum ourNode = getNodeNum();
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability)
// - not DSR routing)
if (p->want_ack) { if (p->want_ack) {
if (MeshModule::currentReply) if (MeshModule::currentReply)
DEBUG_MSG("Some other module has replied to this message, no need for a 2nd ack\n"); DEBUG_MSG("Some other module has replied to this message, no need for a 2nd ack\n");
else else
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel); if (p->which_payload_variant == MeshPacket_decoded_tag)
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
else
// Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded
sendAckNak(Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex());
} }
// We consider an ack to be either a !routing packet with a request ID or a routing packet with !error // We consider an ack to be either a !routing packet with a request ID or a routing packet with !error
@@ -196,8 +199,7 @@ int32_t ReliableRouter::doRetransmissions()
DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
p.packet->id); p.packet->id);
sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel); sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel);
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived
// allows the DSR version to still be able to look at the PendingPacket
stopRetransmission(it->first); stopRetransmission(it->first);
stillValid = false; // just deleted it stillValid = false; // just deleted it
} else { } else {

View File

@@ -38,12 +38,6 @@ struct PendingPacket {
/** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */ /** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */
uint8_t numRetransmissions = 0; uint8_t numRetransmissions = 0;
/** True if we have started trying to find a route - for DSR usage
* While trying to find a route we don't actually send the data packet. We just leave it here pending until
* we have a route or we've failed to find one.
*/
bool wantRoute = false;
PendingPacket() {} PendingPacket() {}
explicit PendingPacket(MeshPacket *p); explicit PendingPacket(MeshPacket *p);
}; };

View File

@@ -2,6 +2,7 @@
#include "Channels.h" #include "Channels.h"
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "MeshRadio.h"
#include "RTC.h" #include "RTC.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
@@ -21,7 +22,6 @@ extern "C" {
* DONE: Implement basic interface and use it elsewhere in app * DONE: Implement basic interface and use it elsewhere in app
* Add naive flooding mixin (& drop duplicate rx broadcasts), add tools for sending broadcasts with incrementing sequence #s * Add naive flooding mixin (& drop duplicate rx broadcasts), add tools for sending broadcasts with incrementing sequence #s
* Add an optional adjacent node only 'send with ack' mixin. If we timeout waiting for the ack, call handleAckTimeout(packet) * Add an optional adjacent node only 'send with ack' mixin. If we timeout waiting for the ack, call handleAckTimeout(packet)
* Add DSR mixin
* *
**/ **/
@@ -188,6 +188,18 @@ ErrorCode Router::send(MeshPacket *p)
{ {
assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal
// Abort sending if we are violating the duty cycle
if (!config.lora.override_duty_cycle && myRegion->dutyCycle != 100) {
float hourlyTxPercent = airTime->utilizationTXPercent();
if (hourlyTxPercent > myRegion->dutyCycle) {
uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle);
DEBUG_MSG("WARNING: Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes);
Routing_Error err = Routing_Error_DUTY_CYCLE_LIMIT;
abortSendAndNak(err, p);
return err;
}
}
// PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; // PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
// assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with // assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with
// assert // assert

View File

@@ -12,6 +12,7 @@ SX126xInterface<T>::SX126xInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq,
SPIClass &spi) SPIClass &spi)
: RadioLibInterface(cs, irq, rst, busy, spi, &lora), lora(&module) : RadioLibInterface(cs, irq, rst, busy, spi, &lora), lora(&module)
{ {
DEBUG_MSG("SX126xInterface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
} }
/// Initialise the Driver transport hardware and software. /// Initialise the Driver transport hardware and software.
@@ -25,11 +26,11 @@ bool SX126xInterface<T>::init()
pinMode(SX126X_POWER_EN, OUTPUT); pinMode(SX126X_POWER_EN, OUTPUT);
#endif #endif
#ifdef SX126X_RXEN // set not rx or tx mode #if defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC) // set not rx or tx mode
digitalWrite(SX126X_RXEN, LOW); // Set low before becoming an output digitalWrite(SX126X_RXEN, LOW); // Set low before becoming an output
pinMode(SX126X_RXEN, OUTPUT); pinMode(SX126X_RXEN, OUTPUT);
#endif #endif
#ifdef SX126X_TXEN #if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
digitalWrite(SX126X_TXEN, LOW); digitalWrite(SX126X_TXEN, LOW);
pinMode(SX126X_TXEN, OUTPUT); pinMode(SX126X_TXEN, OUTPUT);
#endif #endif
@@ -56,9 +57,9 @@ bool SX126xInterface<T>::init()
// \todo Display actual typename of the adapter, not just `SX126x` // \todo Display actual typename of the adapter, not just `SX126x`
DEBUG_MSG("SX126x init result %d\n", res); DEBUG_MSG("SX126x init result %d\n", res);
DEBUG_MSG("Frequency set to %f\n", getFreq()); DEBUG_MSG("Frequency set to %f\n", getFreq());
DEBUG_MSG("Bandwidth set to %f\n", bw); DEBUG_MSG("Bandwidth set to %f\n", bw);
DEBUG_MSG("Power output set to %d\n", power); DEBUG_MSG("Power output set to %d\n", power);
// current limit was removed from module' ctor // current limit was removed from module' ctor
// override default value (60 mA) // override default value (60 mA)
@@ -66,10 +67,10 @@ bool SX126xInterface<T>::init()
DEBUG_MSG("Current limit set to %f\n", currentLimit); DEBUG_MSG("Current limit set to %f\n", currentLimit);
DEBUG_MSG("Current limit set result %d\n", res); DEBUG_MSG("Current limit set result %d\n", res);
#ifdef SX126X_TXEN #if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX // lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
if (res == RADIOLIB_ERR_NONE) if (res == RADIOLIB_ERR_NONE)
res = lora.setDio2AsRfSwitch(true); res = lora.setDio2AsRfSwitch(false);
#endif #endif
#if 0 #if 0
@@ -81,11 +82,11 @@ bool SX126xInterface<T>::init()
//if(crcLSB != 0x0f) //if(crcLSB != 0x0f)
// RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure); // RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
crcLSB = 0x5a; crcLSB = 0x5a;
err = lora.writeRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1); err = lora.writeRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
if(err != RADIOLIB_ERR_NONE) if(err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure); RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1); err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
if(err != RADIOLIB_ERR_NONE) if(err != RADIOLIB_ERR_NONE)
@@ -144,8 +145,9 @@ bool SX126xInterface<T>::reconfigure()
if (err != RADIOLIB_ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING); RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);
if (power > 22) // This chip has lower power limits than some if (power > SX126X_MAX_POWER) // This chip has lower power limits than some
power = 22; power = SX126X_MAX_POWER;
err = lora.setOutputPower(power); err = lora.setOutputPower(power);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
@@ -164,14 +166,18 @@ template<typename T>
void SX126xInterface<T>::setStandby() void SX126xInterface<T>::setStandby()
{ {
checkNotification(); // handle any pending interrupts before we force standby checkNotification(); // handle any pending interrupts before we force standby
int err = lora.standby(); int err = lora.standby();
if (err != RADIOLIB_ERR_NONE)
DEBUG_MSG("SX126x standby failed with error %d\n", err);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
#ifdef SX126X_RXEN // we have RXEN/TXEN control - turn off RX and TX power #if defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power
digitalWrite(SX126X_RXEN, LOW); digitalWrite(SX126X_RXEN, LOW);
#endif #endif
#ifdef SX126X_TXEN #if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
digitalWrite(SX126X_TXEN, LOW); digitalWrite(SX126X_TXEN, LOW);
#endif #endif
@@ -196,10 +202,10 @@ void SX126xInterface<T>::addReceiveMetadata(MeshPacket *mp)
template<typename T> template<typename T>
void SX126xInterface<T>::configHardwareForSend() void SX126xInterface<T>::configHardwareForSend()
{ {
#ifdef SX126X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power #if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on TX power / off RX power
digitalWrite(SX126X_TXEN, HIGH); digitalWrite(SX126X_TXEN, HIGH);
#endif #endif
#ifdef SX126X_RXEN #if defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC)
digitalWrite(SX126X_RXEN, LOW); digitalWrite(SX126X_RXEN, LOW);
#endif #endif
@@ -218,13 +224,13 @@ void SX126xInterface<T>::startReceive()
setStandby(); setStandby();
#ifdef SX126X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power #if defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on RX power / off TX power
digitalWrite(SX126X_RXEN, HIGH); digitalWrite(SX126X_RXEN, HIGH);
#endif #endif
#ifdef SX126X_TXEN #if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
digitalWrite(SX126X_TXEN, LOW); digitalWrite(SX126X_TXEN, LOW);
#endif #endif
// int err = lora.startReceive(); // int err = lora.startReceive();
int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in
// standby mostly. // standby mostly.
@@ -244,13 +250,13 @@ bool SX126xInterface<T>::isChannelActive()
// check if we can detect a LoRa preamble on the current channel // check if we can detect a LoRa preamble on the current channel
int16_t result; int16_t result;
setStandby(); setStandby();
result = lora.scanChannel(); result = lora.scanChannel();
if (result == RADIOLIB_PREAMBLE_DETECTED) if (result == RADIOLIB_PREAMBLE_DETECTED)
return true; return true;
assert(result != RADIOLIB_ERR_WRONG_MODEM); assert(result != RADIOLIB_ERR_WRONG_MODEM);
return false; return false;
} }

View File

@@ -2,12 +2,8 @@
#include "SX1280Interface.h" #include "SX1280Interface.h"
#include "error.h" #include "error.h"
#if !defined(ARCH_PORTDUINO)
SX1280Interface::SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SX1280Interface::SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
SPIClass &spi) SPIClass &spi)
: SX128xInterface(cs, irq, rst, busy, spi) : SX128xInterface(cs, irq, rst, busy, spi)
{ {
} }
#endif

View File

@@ -6,12 +6,9 @@
* Our adapter for SX1280 radios * Our adapter for SX1280 radios
*/ */
#if !defined(ARCH_PORTDUINO)
class SX1280Interface : public SX128xInterface<SX1280> class SX1280Interface : public SX128xInterface<SX1280>
{ {
public: public:
SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi); SX1280Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
}; };
#endif

View File

@@ -2,11 +2,9 @@
#include "SX128xInterface.h" #include "SX128xInterface.h"
#include "error.h" #include "error.h"
#if !defined(ARCH_PORTDUINO)
// Particular boards might define a different max power based on what their hardware can do // Particular boards might define a different max power based on what their hardware can do
#ifndef SX128X_MAX_POWER #ifndef SX128X_MAX_POWER
#define SX128X_MAX_POWER 22 #define SX128X_MAX_POWER 13
#endif #endif
template<typename T> template<typename T>
@@ -27,11 +25,11 @@ bool SX128xInterface<T>::init()
pinMode(SX128X_POWER_EN, OUTPUT); pinMode(SX128X_POWER_EN, OUTPUT);
#endif #endif
#ifdef SX128X_RXEN // set not rx or tx mode #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode
digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output
pinMode(SX128X_RXEN, OUTPUT); pinMode(SX128X_RXEN, OUTPUT);
#endif #endif
#ifdef SX128X_TXEN #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
digitalWrite(SX128X_TXEN, LOW); digitalWrite(SX128X_TXEN, LOW);
pinMode(SX128X_TXEN, OUTPUT); pinMode(SX128X_TXEN, OUTPUT);
#endif #endif
@@ -46,6 +44,8 @@ bool SX128xInterface<T>::init()
limitPower(); limitPower();
preambleLength = 12; // 12 is the default for this chip, 32 does not RX at all
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength); int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength);
// \todo Display actual typename of the adapter, not just `SX128x` // \todo Display actual typename of the adapter, not just `SX128x`
DEBUG_MSG("SX128x init result %d\n", res); DEBUG_MSG("SX128x init result %d\n", res);
@@ -54,14 +54,8 @@ bool SX128xInterface<T>::init()
DEBUG_MSG("Bandwidth set to %f\n", bw); DEBUG_MSG("Bandwidth set to %f\n", bw);
DEBUG_MSG("Power output set to %d\n", power); DEBUG_MSG("Power output set to %d\n", power);
#ifdef SX128X_TXEN
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
if (res == RADIOLIB_ERR_NONE) if (res == RADIOLIB_ERR_NONE)
res = lora.setDio2AsRfSwitch(true); res = lora.setCRC(2);
#endif
if (res == RADIOLIB_ERR_NONE)
res = lora.setCRC(RADIOLIB_SX128X_LORA_CRC_ON);
if (res == RADIOLIB_ERR_NONE) if (res == RADIOLIB_ERR_NONE)
startReceive(); // start receiving startReceive(); // start receiving
@@ -105,8 +99,9 @@ bool SX128xInterface<T>::reconfigure()
if (err != RADIOLIB_ERR_NONE) if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING); RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);
if (power > 22) // This chip has lower power limits than some if (power > SX128X_MAX_POWER) // This chip has lower power limits than some
power = 22; power = SX128X_MAX_POWER;
err = lora.setOutputPower(power); err = lora.setOutputPower(power);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
@@ -121,18 +116,28 @@ void INTERRUPT_ATTR SX128xInterface<T>::disableInterrupt()
lora.clearDio1Action(); lora.clearDio1Action();
} }
template<typename T>
bool SX128xInterface<T>::wideLora()
{
return true;
}
template<typename T> template<typename T>
void SX128xInterface<T>::setStandby() void SX128xInterface<T>::setStandby()
{ {
checkNotification(); // handle any pending interrupts before we force standby checkNotification(); // handle any pending interrupts before we force standby
int err = lora.standby(); int err = lora.standby();
if (err != RADIOLIB_ERR_NONE)
DEBUG_MSG("SX128x standby failed with error %d\n", err);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
#ifdef SX128X_RXEN // we have RXEN/TXEN control - turn off RX and TX power #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power
digitalWrite(SX128X_RXEN, LOW); digitalWrite(SX128X_RXEN, LOW);
#endif #endif
#ifdef SX128X_TXEN #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
digitalWrite(SX128X_TXEN, LOW); digitalWrite(SX128X_TXEN, LOW);
#endif #endif
@@ -157,10 +162,10 @@ void SX128xInterface<T>::addReceiveMetadata(MeshPacket *mp)
template<typename T> template<typename T>
void SX128xInterface<T>::configHardwareForSend() void SX128xInterface<T>::configHardwareForSend()
{ {
#ifdef SX128X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on TX power / off RX power
digitalWrite(SX128X_TXEN, HIGH); digitalWrite(SX128X_TXEN, HIGH);
#endif #endif
#ifdef SX128X_RXEN #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC)
digitalWrite(SX128X_RXEN, LOW); digitalWrite(SX128X_RXEN, LOW);
#endif #endif
@@ -179,10 +184,10 @@ void SX128xInterface<T>::startReceive()
setStandby(); setStandby();
#ifdef SX128X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn on RX power / off TX power
digitalWrite(SX128X_RXEN, HIGH); digitalWrite(SX128X_RXEN, HIGH);
#endif #endif
#ifdef SX128X_TXEN #if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
digitalWrite(SX128X_TXEN, LOW); digitalWrite(SX128X_TXEN, LOW);
#endif #endif
@@ -218,7 +223,13 @@ bool SX128xInterface<T>::isChannelActive()
template<typename T> template<typename T>
bool SX128xInterface<T>::isActivelyReceiving() bool SX128xInterface<T>::isActivelyReceiving()
{ {
#ifdef RADIOLIB_GODMODE
uint16_t irq = lora.getIrqStatus();
bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID);
return hasPreamble;
#else
return isChannelActive(); return isChannelActive();
#endif
} }
template<typename T> template<typename T>
@@ -243,5 +254,3 @@ bool SX128xInterface<T>::sleep()
return true; return true;
} }
#endif

View File

@@ -1,7 +1,5 @@
#pragma once #pragma once
#if !defined(ARCH_PORTDUINO)
#include "RadioLibInterface.h" #include "RadioLibInterface.h"
/** /**
@@ -19,6 +17,8 @@ class SX128xInterface : public RadioLibInterface
/// \return true if initialisation succeeded. /// \return true if initialisation succeeded.
virtual bool init() override; virtual bool init() override;
virtual bool wideLora() override;
/// Apply any radio provisioning changes /// Apply any radio provisioning changes
/// Make sure the Driver is properly configured before calling init(). /// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded. /// \return true if initialisation succeeded.
@@ -27,9 +27,11 @@ class SX128xInterface : public RadioLibInterface
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep. /// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
virtual bool sleep() override; virtual bool sleep() override;
protected: #ifdef RADIOLIB_GODMODE
bool isIRQPending() override { return lora.getIrqStatus() != 0; }
#endif
float currentLimit = 140; // Higher OCP limit for SX128x PA protected:
/** /**
* Specific module instance * Specific module instance
@@ -71,5 +73,3 @@ class SX128xInterface : public RadioLibInterface
private: private:
}; };
#endif

View File

@@ -82,10 +82,11 @@ typedef struct _AdminMessage {
ModuleConfig set_module_config; ModuleConfig set_module_config;
/* Set the Canned Message Module messages text. */ /* Set the Canned Message Module messages text. */
char set_canned_message_module_messages[201]; char set_canned_message_module_messages[201];
/* Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins */ /* Begins an edit transaction for config, module config, owner, and channel settings changes
bool confirm_set_config; This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */
/* Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins */ bool begin_edit_settings;
bool confirm_set_module_config; /* Commits an open transaction for any edits made to config, module config, owner, and channel settings */
bool commit_edit_settings;
/* Setting channels/radio config remotely carries the risk that you might send an invalid config and the radio never talks to your mesh again. /* Setting channels/radio config remotely carries the risk that you might send an invalid config and the radio never talks to your mesh again.
Therefore if setting either of these properties remotely, you must send a confirm_xxx message within 10 minutes. Therefore if setting either of these properties remotely, you must send a confirm_xxx message within 10 minutes.
If you fail to do so, the radio will assume loss of comms and revert your changes. If you fail to do so, the radio will assume loss of comms and revert your changes.
@@ -147,8 +148,8 @@ extern "C" {
#define AdminMessage_set_config_tag 34 #define AdminMessage_set_config_tag 34
#define AdminMessage_set_module_config_tag 35 #define AdminMessage_set_module_config_tag 35
#define AdminMessage_set_canned_message_module_messages_tag 36 #define AdminMessage_set_canned_message_module_messages_tag 36
#define AdminMessage_confirm_set_config_tag 64 #define AdminMessage_begin_edit_settings_tag 64
#define AdminMessage_confirm_set_module_config_tag 65 #define AdminMessage_commit_edit_settings_tag 65
#define AdminMessage_confirm_set_channel_tag 66 #define AdminMessage_confirm_set_channel_tag 66
#define AdminMessage_confirm_set_radio_tag 67 #define AdminMessage_confirm_set_radio_tag 67
#define AdminMessage_reboot_ota_seconds_tag 95 #define AdminMessage_reboot_ota_seconds_tag 95
@@ -177,8 +178,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 3
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_module_config,set_module_config), 35) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_module_config,set_module_config), 35) \
X(a, STATIC, ONEOF, STRING, (payload_variant,set_canned_message_module_messages,set_canned_message_module_messages), 36) \ X(a, STATIC, ONEOF, STRING, (payload_variant,set_canned_message_module_messages,set_canned_message_module_messages), 36) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_config,confirm_set_config), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_module_config,confirm_set_module_config), 65) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_channel,confirm_set_channel), 66) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_channel,confirm_set_channel), 66) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_radio,confirm_set_radio), 67) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_radio,confirm_set_radio), 67) \
X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \

View File

@@ -54,7 +54,7 @@ extern const pb_msgdesc_t ChannelSet_msg;
#define ChannelSet_fields &ChannelSet_msg #define ChannelSet_fields &ChannelSet_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define ChannelSet_size 582 #define ChannelSet_size 584
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -100,6 +100,8 @@ typedef struct _Config_DeviceConfig {
Config_DeviceConfig_Role role; Config_DeviceConfig_Role role;
bool serial_enabled; bool serial_enabled;
bool debug_log_enabled; bool debug_log_enabled;
uint32_t button_gpio;
uint32_t buzzer_gpio;
} Config_DeviceConfig; } Config_DeviceConfig;
typedef struct _Config_DisplayConfig { typedef struct _Config_DisplayConfig {
@@ -124,6 +126,7 @@ typedef struct _Config_LoRaConfig {
bool tx_enabled; bool tx_enabled;
int8_t tx_power; int8_t tx_power;
uint16_t channel_num; uint16_t channel_num;
bool override_duty_cycle;
pb_size_t ignore_incoming_count; pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3]; uint32_t ignore_incoming[3];
} Config_LoRaConfig; } Config_LoRaConfig;
@@ -143,6 +146,8 @@ typedef struct _Config_PositionConfig {
uint32_t gps_update_interval; uint32_t gps_update_interval;
uint32_t gps_attempt_time; uint32_t gps_attempt_time;
uint32_t position_flags; uint32_t position_flags;
uint32_t rx_gpio;
uint32_t tx_gpio;
} Config_PositionConfig; } Config_PositionConfig;
typedef struct _Config_PowerConfig { typedef struct _Config_PowerConfig {
@@ -225,22 +230,22 @@ extern "C" {
/* Initializer values for message structs */ /* Initializer values for message structs */
#define Config_init_default {0, {Config_DeviceConfig_init_default}} #define Config_init_default {0, {Config_DeviceConfig_init_default}}
#define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0} #define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0} #define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0} #define Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
#define Config_NetworkConfig_init_default {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default} #define Config_NetworkConfig_init_default {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default}
#define Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} #define Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
#define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN} #define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN}
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}} #define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define Config_BluetoothConfig_init_default {0, _Config_BluetoothConfig_PairingMode_MIN, 0} #define Config_BluetoothConfig_init_default {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}} #define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0} #define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0} #define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0} #define Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
#define Config_NetworkConfig_init_zero {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero} #define Config_NetworkConfig_init_zero {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero}
#define Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} #define Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
#define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN} #define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN}
#define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}} #define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define Config_BluetoothConfig_init_zero {0, _Config_BluetoothConfig_PairingMode_MIN, 0} #define Config_BluetoothConfig_init_zero {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
@@ -250,6 +255,8 @@ extern "C" {
#define Config_DeviceConfig_role_tag 1 #define Config_DeviceConfig_role_tag 1
#define Config_DeviceConfig_serial_enabled_tag 2 #define Config_DeviceConfig_serial_enabled_tag 2
#define Config_DeviceConfig_debug_log_enabled_tag 3 #define Config_DeviceConfig_debug_log_enabled_tag 3
#define Config_DeviceConfig_button_gpio_tag 4
#define Config_DeviceConfig_buzzer_gpio_tag 5
#define Config_DisplayConfig_screen_on_secs_tag 1 #define Config_DisplayConfig_screen_on_secs_tag 1
#define Config_DisplayConfig_gps_format_tag 2 #define Config_DisplayConfig_gps_format_tag 2
#define Config_DisplayConfig_auto_screen_carousel_secs_tag 3 #define Config_DisplayConfig_auto_screen_carousel_secs_tag 3
@@ -268,6 +275,7 @@ extern "C" {
#define Config_LoRaConfig_tx_enabled_tag 9 #define Config_LoRaConfig_tx_enabled_tag 9
#define Config_LoRaConfig_tx_power_tag 10 #define Config_LoRaConfig_tx_power_tag 10
#define Config_LoRaConfig_channel_num_tag 11 #define Config_LoRaConfig_channel_num_tag 11
#define Config_LoRaConfig_override_duty_cycle_tag 12
#define Config_LoRaConfig_ignore_incoming_tag 103 #define Config_LoRaConfig_ignore_incoming_tag 103
#define Config_NetworkConfig_IpV4Config_ip_tag 1 #define Config_NetworkConfig_IpV4Config_ip_tag 1
#define Config_NetworkConfig_IpV4Config_gateway_tag 2 #define Config_NetworkConfig_IpV4Config_gateway_tag 2
@@ -280,6 +288,8 @@ extern "C" {
#define Config_PositionConfig_gps_update_interval_tag 5 #define Config_PositionConfig_gps_update_interval_tag 5
#define Config_PositionConfig_gps_attempt_time_tag 6 #define Config_PositionConfig_gps_attempt_time_tag 6
#define Config_PositionConfig_position_flags_tag 7 #define Config_PositionConfig_position_flags_tag 7
#define Config_PositionConfig_rx_gpio_tag 8
#define Config_PositionConfig_tx_gpio_tag 9
#define Config_PowerConfig_is_power_saving_tag 1 #define Config_PowerConfig_is_power_saving_tag 1
#define Config_PowerConfig_on_battery_shutdown_after_secs_tag 2 #define Config_PowerConfig_on_battery_shutdown_after_secs_tag 2
#define Config_PowerConfig_adc_multiplier_override_tag 3 #define Config_PowerConfig_adc_multiplier_override_tag 3
@@ -325,7 +335,9 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,bluetooth,payload_variant.bl
#define Config_DeviceConfig_FIELDLIST(X, a) \ #define Config_DeviceConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, role, 1) \ X(a, STATIC, SINGULAR, UENUM, role, 1) \
X(a, STATIC, SINGULAR, BOOL, serial_enabled, 2) \ X(a, STATIC, SINGULAR, BOOL, serial_enabled, 2) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 3) X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 3) \
X(a, STATIC, SINGULAR, UINT32, button_gpio, 4) \
X(a, STATIC, SINGULAR, UINT32, buzzer_gpio, 5)
#define Config_DeviceConfig_CALLBACK NULL #define Config_DeviceConfig_CALLBACK NULL
#define Config_DeviceConfig_DEFAULT NULL #define Config_DeviceConfig_DEFAULT NULL
@@ -336,7 +348,9 @@ X(a, STATIC, SINGULAR, BOOL, fixed_position, 3) \
X(a, STATIC, SINGULAR, BOOL, gps_enabled, 4) \ X(a, STATIC, SINGULAR, BOOL, gps_enabled, 4) \
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 5) \ X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 5) \
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 6) \ X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 6) \
X(a, STATIC, SINGULAR, UINT32, position_flags, 7) X(a, STATIC, SINGULAR, UINT32, position_flags, 7) \
X(a, STATIC, SINGULAR, UINT32, rx_gpio, 8) \
X(a, STATIC, SINGULAR, UINT32, tx_gpio, 9)
#define Config_PositionConfig_CALLBACK NULL #define Config_PositionConfig_CALLBACK NULL
#define Config_PositionConfig_DEFAULT NULL #define Config_PositionConfig_DEFAULT NULL
@@ -395,6 +409,7 @@ X(a, STATIC, SINGULAR, UINT32, hop_limit, 8) \
X(a, STATIC, SINGULAR, BOOL, tx_enabled, 9) \ X(a, STATIC, SINGULAR, BOOL, tx_enabled, 9) \
X(a, STATIC, SINGULAR, INT32, tx_power, 10) \ X(a, STATIC, SINGULAR, INT32, tx_power, 10) \
X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \ X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \
X(a, STATIC, SINGULAR, BOOL, override_duty_cycle, 12) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
#define Config_LoRaConfig_CALLBACK NULL #define Config_LoRaConfig_CALLBACK NULL
#define Config_LoRaConfig_DEFAULT NULL #define Config_LoRaConfig_DEFAULT NULL
@@ -429,12 +444,12 @@ extern const pb_msgdesc_t Config_BluetoothConfig_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define Config_BluetoothConfig_size 10 #define Config_BluetoothConfig_size 10
#define Config_DeviceConfig_size 6 #define Config_DeviceConfig_size 18
#define Config_DisplayConfig_size 22 #define Config_DisplayConfig_size 22
#define Config_LoRaConfig_size 68 #define Config_LoRaConfig_size 70
#define Config_NetworkConfig_IpV4Config_size 20 #define Config_NetworkConfig_IpV4Config_size 20
#define Config_NetworkConfig_size 161 #define Config_NetworkConfig_size 161
#define Config_PositionConfig_size 30 #define Config_PositionConfig_size 42
#define Config_PowerConfig_size 43 #define Config_PowerConfig_size 43
#define Config_size 164 #define Config_size 164

View File

@@ -150,8 +150,8 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
#define LocalModuleConfig_fields &LocalModuleConfig_msg #define LocalModuleConfig_fields &LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define LocalConfig_size 361 #define LocalConfig_size 387
#define LocalModuleConfig_size 294 #define LocalModuleConfig_size 358
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -78,6 +78,10 @@ typedef enum _HardwareModel {
HardwareModel_DR_DEV = 41, HardwareModel_DR_DEV = 41,
/* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/ */ /* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/ */
HardwareModel_M5STACK = 42, HardwareModel_M5STACK = 42,
/* New Heltec LoRA32 with ESP32-S3 CPU */
HardwareModel_HELTEC_V3 = 43,
/* New Heltec Wireless Stick Lite with ESP32-S3 CPU */
HardwareModel_HELTEC_WSL_V3 = 44,
/* Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. */ /* Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. */
HardwareModel_PRIVATE_HW = 255 HardwareModel_PRIVATE_HW = 255
} HardwareModel; } HardwareModel;
@@ -181,9 +185,11 @@ typedef enum _Routing_Error {
/* TODO: REPLACE */ /* TODO: REPLACE */
Routing_Error_NO_RESPONSE = 8, Routing_Error_NO_RESPONSE = 8,
/* TODO: REPLACE */ /* TODO: REPLACE */
Routing_Error_BAD_REQUEST = 32, Routing_Error_DUTY_CYCLE_LIMIT = 9,
/* The new version of the heltec WiFi_Lora_32_V2 board that has battery sensing hooked to GPIO 37. /* The new version of the heltec WiFi_Lora_32_V2 board that has battery sensing hooked to GPIO 37.
Sadly they did not update anything on the silkscreen to identify this board */ Sadly they did not update anything on the silkscreen to identify this board */
Routing_Error_BAD_REQUEST = 32,
/* Ancient heltec WiFi_Lora_32 board */
Routing_Error_NOT_AUTHORIZED = 33 Routing_Error_NOT_AUTHORIZED = 33
} Routing_Error; } Routing_Error;
@@ -501,7 +507,7 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
typedef struct _MeshPacket { typedef struct _MeshPacket {
/* The sending node number. /* The sending node number.
Note: Our crypto implementation uses this field as well. Note: Our crypto implementation uses this field as well.
See [crypto](/docs/about/overview/encryption) for details. See [crypto](/docs/overview/encryption) for details.
FIXME - really should be fixed32 instead, this encoding only hurts the ble link though. */ FIXME - really should be fixed32 instead, this encoding only hurts the ble link though. */
uint32_t from; uint32_t from;
/* The (immediatSee Priority description for more details.y should be fixed32 instead, this encoding only /* The (immediatSee Priority description for more details.y should be fixed32 instead, this encoding only
@@ -529,7 +535,7 @@ typedef struct _MeshPacket {
needs to be unique for a few minutes (long enough to last for the length of needs to be unique for a few minutes (long enough to last for the length of
any ACK or the completion of a mesh broadcast flood). any ACK or the completion of a mesh broadcast flood).
Note: Our crypto implementation uses this id as well. Note: Our crypto implementation uses this id as well.
See [crypto](/docs/about/overview/encryption) for details. See [crypto](/docs/overview/encryption) for details.
FIXME - really should be fixed32 instead, this encoding only FIXME - really should be fixed32 instead, this encoding only
hurts the ble link though. */ hurts the ble link though. */
uint32_t id; uint32_t id;

View File

@@ -63,10 +63,12 @@ typedef enum _ModuleConfig_CannedMessageConfig_InputEventChar {
/* Struct definitions */ /* Struct definitions */
typedef struct _ModuleConfig_AudioConfig { typedef struct _ModuleConfig_AudioConfig {
bool codec2_enabled; bool codec2_enabled;
uint32_t mic_chan; uint8_t ptt_pin;
uint32_t amp_pin;
uint32_t ptt_pin;
ModuleConfig_AudioConfig_Audio_Baud bitrate; ModuleConfig_AudioConfig_Audio_Baud bitrate;
uint8_t i2s_ws;
uint8_t i2s_sd;
uint8_t i2s_din;
uint8_t i2s_sck;
} ModuleConfig_AudioConfig; } ModuleConfig_AudioConfig;
typedef struct _ModuleConfig_CannedMessageConfig { typedef struct _ModuleConfig_CannedMessageConfig {
@@ -90,13 +92,14 @@ typedef struct _ModuleConfig_ExternalNotificationConfig {
bool active; bool active;
bool alert_message; bool alert_message;
bool alert_bell; bool alert_bell;
bool use_pwm;
} ModuleConfig_ExternalNotificationConfig; } ModuleConfig_ExternalNotificationConfig;
typedef struct _ModuleConfig_MQTTConfig { typedef struct _ModuleConfig_MQTTConfig {
bool enabled; bool enabled;
char address[32]; char address[32];
char username[32]; char username[64];
char password[32]; char password[64];
bool encryption_enabled; bool encryption_enabled;
bool json_enabled; bool json_enabled;
} ModuleConfig_MQTTConfig; } ModuleConfig_MQTTConfig;
@@ -182,18 +185,18 @@ extern "C" {
/* Initializer values for message structs */ /* Initializer values for message structs */
#define ModuleConfig_init_default {0, {ModuleConfig_MQTTConfig_init_default}} #define ModuleConfig_init_default {0, {ModuleConfig_MQTTConfig_init_default}}
#define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0} #define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0}
#define ModuleConfig_AudioConfig_init_default {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN} #define ModuleConfig_AudioConfig_init_default {0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN} #define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0} #define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0}
#define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0} #define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
#define ModuleConfig_RangeTestConfig_init_default {0, 0, 0} #define ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
#define ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0} #define ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0}
#define ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define ModuleConfig_init_zero {0, {ModuleConfig_MQTTConfig_init_zero}} #define ModuleConfig_init_zero {0, {ModuleConfig_MQTTConfig_init_zero}}
#define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0} #define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0}
#define ModuleConfig_AudioConfig_init_zero {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN} #define ModuleConfig_AudioConfig_init_zero {0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN} #define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0} #define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
#define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0} #define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
#define ModuleConfig_RangeTestConfig_init_zero {0, 0, 0} #define ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
#define ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0} #define ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0}
@@ -201,10 +204,12 @@ extern "C" {
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define ModuleConfig_AudioConfig_codec2_enabled_tag 1 #define ModuleConfig_AudioConfig_codec2_enabled_tag 1
#define ModuleConfig_AudioConfig_mic_chan_tag 2 #define ModuleConfig_AudioConfig_ptt_pin_tag 2
#define ModuleConfig_AudioConfig_amp_pin_tag 3 #define ModuleConfig_AudioConfig_bitrate_tag 3
#define ModuleConfig_AudioConfig_ptt_pin_tag 4 #define ModuleConfig_AudioConfig_i2s_ws_tag 4
#define ModuleConfig_AudioConfig_bitrate_tag 5 #define ModuleConfig_AudioConfig_i2s_sd_tag 5
#define ModuleConfig_AudioConfig_i2s_din_tag 6
#define ModuleConfig_AudioConfig_i2s_sck_tag 7
#define ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1 #define ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1
#define ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2 #define ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2
#define ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3 #define ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3
@@ -222,6 +227,7 @@ extern "C" {
#define ModuleConfig_ExternalNotificationConfig_active_tag 4 #define ModuleConfig_ExternalNotificationConfig_active_tag 4
#define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5 #define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5
#define ModuleConfig_ExternalNotificationConfig_alert_bell_tag 6 #define ModuleConfig_ExternalNotificationConfig_alert_bell_tag 6
#define ModuleConfig_ExternalNotificationConfig_use_pwm_tag 7
#define ModuleConfig_MQTTConfig_enabled_tag 1 #define ModuleConfig_MQTTConfig_enabled_tag 1
#define ModuleConfig_MQTTConfig_address_tag 2 #define ModuleConfig_MQTTConfig_address_tag 2
#define ModuleConfig_MQTTConfig_username_tag 3 #define ModuleConfig_MQTTConfig_username_tag 3
@@ -290,10 +296,12 @@ X(a, STATIC, SINGULAR, BOOL, json_enabled, 6)
#define ModuleConfig_AudioConfig_FIELDLIST(X, a) \ #define ModuleConfig_AudioConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, codec2_enabled, 1) \ X(a, STATIC, SINGULAR, BOOL, codec2_enabled, 1) \
X(a, STATIC, SINGULAR, UINT32, mic_chan, 2) \ X(a, STATIC, SINGULAR, UINT32, ptt_pin, 2) \
X(a, STATIC, SINGULAR, UINT32, amp_pin, 3) \ X(a, STATIC, SINGULAR, UENUM, bitrate, 3) \
X(a, STATIC, SINGULAR, UINT32, ptt_pin, 4) \ X(a, STATIC, SINGULAR, UINT32, i2s_ws, 4) \
X(a, STATIC, SINGULAR, UENUM, bitrate, 5) X(a, STATIC, SINGULAR, UINT32, i2s_sd, 5) \
X(a, STATIC, SINGULAR, UINT32, i2s_din, 6) \
X(a, STATIC, SINGULAR, UINT32, i2s_sck, 7)
#define ModuleConfig_AudioConfig_CALLBACK NULL #define ModuleConfig_AudioConfig_CALLBACK NULL
#define ModuleConfig_AudioConfig_DEFAULT NULL #define ModuleConfig_AudioConfig_DEFAULT NULL
@@ -314,7 +322,8 @@ X(a, STATIC, SINGULAR, UINT32, output_ms, 2) \
X(a, STATIC, SINGULAR, UINT32, output, 3) \ X(a, STATIC, SINGULAR, UINT32, output, 3) \
X(a, STATIC, SINGULAR, BOOL, active, 4) \ X(a, STATIC, SINGULAR, BOOL, active, 4) \
X(a, STATIC, SINGULAR, BOOL, alert_message, 5) \ X(a, STATIC, SINGULAR, BOOL, alert_message, 5) \
X(a, STATIC, SINGULAR, BOOL, alert_bell, 6) X(a, STATIC, SINGULAR, BOOL, alert_bell, 6) \
X(a, STATIC, SINGULAR, BOOL, use_pwm, 7)
#define ModuleConfig_ExternalNotificationConfig_CALLBACK NULL #define ModuleConfig_ExternalNotificationConfig_CALLBACK NULL
#define ModuleConfig_ExternalNotificationConfig_DEFAULT NULL #define ModuleConfig_ExternalNotificationConfig_DEFAULT NULL
@@ -380,15 +389,15 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg;
#define ModuleConfig_CannedMessageConfig_fields &ModuleConfig_CannedMessageConfig_msg #define ModuleConfig_CannedMessageConfig_fields &ModuleConfig_CannedMessageConfig_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define ModuleConfig_AudioConfig_size 22 #define ModuleConfig_AudioConfig_size 19
#define ModuleConfig_CannedMessageConfig_size 49 #define ModuleConfig_CannedMessageConfig_size 49
#define ModuleConfig_ExternalNotificationConfig_size 20 #define ModuleConfig_ExternalNotificationConfig_size 22
#define ModuleConfig_MQTTConfig_size 105 #define ModuleConfig_MQTTConfig_size 169
#define ModuleConfig_RangeTestConfig_size 10 #define ModuleConfig_RangeTestConfig_size 10
#define ModuleConfig_SerialConfig_size 26 #define ModuleConfig_SerialConfig_size 26
#define ModuleConfig_StoreForwardConfig_size 22 #define ModuleConfig_StoreForwardConfig_size 22
#define ModuleConfig_TelemetryConfig_size 18 #define ModuleConfig_TelemetryConfig_size 18
#define ModuleConfig_size 107 #define ModuleConfig_size 172
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -82,6 +82,9 @@ typedef enum _PortNum {
Maintained by GitHub user GUVWAF. Maintained by GitHub user GUVWAF.
Project files at https://github.com/GUVWAF/Meshtasticator */ Project files at https://github.com/GUVWAF/Meshtasticator */
PortNum_SIMULATOR_APP = 69, PortNum_SIMULATOR_APP = 69,
/* Provides a traceroute functionality to show the route a packet towards
a certain destination would take on the mesh. */
PortNum_TRACEROUTE_APP = 70,
/* Private applications should use portnums >= 256. /* Private applications should use portnums >= 256.
To simplify initial development and testing you can use "PRIVATE_APP" To simplify initial development and testing you can use "PRIVATE_APP"
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */ in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */

View File

@@ -33,7 +33,9 @@ typedef enum _TelemetrySensorType {
/* 3-Axis magnetic sensor */ /* 3-Axis magnetic sensor */
TelemetrySensorType_QMC6310 = 9, TelemetrySensorType_QMC6310 = 9,
/* 6-Axis inertial measurement sensor */ /* 6-Axis inertial measurement sensor */
TelemetrySensorType_QMI8658 = 10 TelemetrySensorType_QMI8658 = 10,
/* 3-Axis magnetic sensor */
TelemetrySensorType_QMC5883L = 11
} TelemetrySensorType; } TelemetrySensorType;
/* Struct definitions */ /* Struct definitions */
@@ -85,8 +87,8 @@ typedef struct _Telemetry {
/* Helper constants for enums */ /* Helper constants for enums */
#define _TelemetrySensorType_MIN TelemetrySensorType_SENSOR_UNSET #define _TelemetrySensorType_MIN TelemetrySensorType_SENSOR_UNSET
#define _TelemetrySensorType_MAX TelemetrySensorType_QMI8658 #define _TelemetrySensorType_MAX TelemetrySensorType_QMC5883L
#define _TelemetrySensorType_ARRAYSIZE ((TelemetrySensorType)(TelemetrySensorType_QMI8658+1)) #define _TelemetrySensorType_ARRAYSIZE ((TelemetrySensorType)(TelemetrySensorType_QMC5883L+1))
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -12,7 +12,7 @@
#include <HTTPBodyParser.hpp> #include <HTTPBodyParser.hpp>
#include <HTTPMultipartBodyParser.hpp> #include <HTTPMultipartBodyParser.hpp>
#include <HTTPURLEncodedBodyParser.hpp> #include <HTTPURLEncodedBodyParser.hpp>
#include <json11.hpp> #include "mqtt/JSON.h"
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
@@ -246,15 +246,15 @@ void htmlDeleteDir(const char *dirname)
root.close(); root.close();
} }
std::vector<std::map<char *, char *>> *htmlListDir(std::vector<std::map<char *, char *>> *fileList, const char *dirname, JSONArray htmlListDir(const char *dirname, uint8_t levels)
uint8_t levels)
{ {
File root = FSCom.open(dirname, FILE_O_READ); File root = FSCom.open(dirname, FILE_O_READ);
JSONArray fileList;
if (!root) { if (!root) {
return NULL; return fileList;
} }
if (!root.isDirectory()) { if (!root.isDirectory()) {
return NULL; return fileList;
} }
// iterate over the file list // iterate over the file list
@@ -263,19 +263,19 @@ std::vector<std::map<char *, char *>> *htmlListDir(std::vector<std::map<char *,
if (file.isDirectory() && !String(file.name()).endsWith(".")) { if (file.isDirectory() && !String(file.name()).endsWith(".")) {
if (levels) { if (levels) {
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
htmlListDir(fileList, file.path(), levels - 1); fileList.push_back(new JSONValue(htmlListDir(file.path(), levels - 1)));
#else #else
htmlListDir(fileList, file.name(), levels - 1); fileList.push_back(new JSONValue(htmlListDir(file.name(), levels - 1)));
#endif #endif
file.close(); file.close();
} }
} else { } else {
std::map<char *, char *> thisFileMap; JSONObject thisFileMap;
thisFileMap[strdup("size")] = strdup(String(file.size()).c_str()); thisFileMap["size"] = new JSONValue((int)file.size());
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
thisFileMap[strdup("name")] = strdup(String(file.path()).substring(1).c_str()); thisFileMap["name"] = new JSONValue(String(file.path()).substring(1).c_str());
#else #else
thisFileMap[strdup("name")] = strdup(String(file.name()).substring(1).c_str()); thisFileMap["name"] = new JSONValue(String(file.name()).substring(1).c_str());
#endif #endif
if (String(file.name()).substring(1).endsWith(".gz")) { if (String(file.name()).substring(1).endsWith(".gz")) {
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
@@ -284,9 +284,9 @@ std::vector<std::map<char *, char *>> *htmlListDir(std::vector<std::map<char *,
String modifiedFile = String(file.name()).substring(1); String modifiedFile = String(file.name()).substring(1);
#endif #endif
modifiedFile.remove((modifiedFile.length() - 3), 3); modifiedFile.remove((modifiedFile.length() - 3), 3);
thisFileMap[strdup("nameModified")] = strdup(modifiedFile.c_str()); thisFileMap["nameModified"] = new JSONValue(modifiedFile.c_str());
} }
fileList->push_back(thisFileMap); fileList.push_back(new JSONValue(thisFileMap));
} }
file.close(); file.close();
file = root.openNextFile(); file = root.openNextFile();
@@ -301,29 +301,31 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
res->setHeader("Access-Control-Allow-Origin", "*"); res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "GET"); res->setHeader("Access-Control-Allow-Methods", "GET");
using namespace json11; auto fileList = htmlListDir("/static", 10);
auto fileList = htmlListDir(new std::vector<std::map<char *, char *>>(), "/static", 10);
// create json output structure // create json output structure
Json filesystemObj = Json::object{ JSONObject filesystemObj;
{"total", String(FSCom.totalBytes()).c_str()}, filesystemObj["total"] = new JSONValue((int)FSCom.totalBytes());
{"used", String(FSCom.usedBytes()).c_str()}, filesystemObj["used"] = new JSONValue((int)FSCom.usedBytes());
{"free", String(FSCom.totalBytes() - FSCom.usedBytes()).c_str()}, filesystemObj["free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));
};
Json jsonObjInner = Json::object{{"files", Json(*fileList)}, {"filesystem", filesystemObj}}; JSONObject jsonObjInner;
jsonObjInner["files"] = new JSONValue(fileList);
jsonObjInner["filesystem"] = new JSONValue(filesystemObj);
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}}; JSONObject jsonObjOuter;
jsonObjOuter["data"] = new JSONValue(jsonObjInner);
jsonObjOuter["status"] = new JSONValue("ok");
// serialize and write it to the stream JSONValue *value = new JSONValue(jsonObjOuter);
std::string jsonStr = jsonObjOuter.dump();
res->print(jsonStr.c_str()); res->print(value->Stringify().c_str());
delete value;
} }
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res) void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
{ {
using namespace json11;
ResourceParameters *params = req->getParams(); ResourceParameters *params = req->getParams();
std::string paramValDelete; std::string paramValDelete;
@@ -334,15 +336,19 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
std::string pathDelete = "/" + paramValDelete; std::string pathDelete = "/" + paramValDelete;
if (FSCom.remove(pathDelete.c_str())) { if (FSCom.remove(pathDelete.c_str())) {
Serial.println(pathDelete.c_str()); Serial.println(pathDelete.c_str());
Json jsonObjOuter = Json::object{{"status", "ok"}}; JSONObject jsonObjOuter;
std::string jsonStr = jsonObjOuter.dump(); jsonObjOuter["status"] = new JSONValue("ok");
res->print(jsonStr.c_str()); JSONValue *value = new JSONValue(jsonObjOuter);
res->print(value->Stringify().c_str());
delete value;
return; return;
} else { } else {
Serial.println(pathDelete.c_str()); Serial.println(pathDelete.c_str());
Json jsonObjOuter = Json::object{{"status", "Error"}}; JSONObject jsonObjOuter;
std::string jsonStr = jsonObjOuter.dump(); jsonObjOuter["status"] = new JSONValue("Error");
res->print(jsonStr.c_str()); JSONValue *value = new JSONValue(jsonObjOuter);
res->print(value->Stringify().c_str());
delete value;
return; return;
} }
} }
@@ -559,8 +565,6 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
void handleReport(HTTPRequest *req, HTTPResponse *res) void handleReport(HTTPRequest *req, HTTPResponse *res)
{ {
using namespace json11;
ResourceParameters *params = req->getParams(); ResourceParameters *params = req->getParams();
std::string content; std::string content;
@@ -579,81 +583,87 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
} }
// data->airtime->tx_log // data->airtime->tx_log
std::vector<String> txLogValues; JSONArray txLogValues;
uint32_t *logArray; uint32_t *logArray;
logArray = airTime->airtimeReport(TX_LOG); logArray = airTime->airtimeReport(TX_LOG);
for (int i = 0; i < airTime->getPeriodsToLog(); i++) { for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
uint32_t tmp; txLogValues.push_back(new JSONValue((int)logArray[i]));
tmp = *(logArray + i);
txLogValues.push_back(String(tmp));
} }
// data->airtime->rx_log // data->airtime->rx_log
std::vector<String> rxLogValues; JSONArray rxLogValues;
logArray = airTime->airtimeReport(RX_LOG); logArray = airTime->airtimeReport(RX_LOG);
for (int i = 0; i < airTime->getPeriodsToLog(); i++) { for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
uint32_t tmp; rxLogValues.push_back(new JSONValue((int)logArray[i]));
tmp = *(logArray + i);
rxLogValues.push_back(String(tmp));
} }
// data->airtime->rx_all_log // data->airtime->rx_all_log
std::vector<String> rxAllLogValues; JSONArray rxAllLogValues;
logArray = airTime->airtimeReport(RX_ALL_LOG); logArray = airTime->airtimeReport(RX_ALL_LOG);
for (int i = 0; i < airTime->getPeriodsToLog(); i++) { for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
uint32_t tmp; rxAllLogValues.push_back(new JSONValue((int)logArray[i]));
tmp = *(logArray + i);
rxAllLogValues.push_back(String(tmp));
} }
Json jsonObjAirtime = Json::object{ // data->airtime
{"tx_log", Json(txLogValues)}, JSONObject jsonObjAirtime;
{"rx_log", Json(rxLogValues)}, jsonObjAirtime["tx_log"] = new JSONValue(txLogValues);
{"rx_all_log", Json(rxAllLogValues)}, jsonObjAirtime["rx_log"] = new JSONValue(rxLogValues);
{"channel_utilization", Json(airTime->channelUtilizationPercent())}, jsonObjAirtime["rx_all_log"] = new JSONValue(rxAllLogValues);
{"utilization_tx", Json(airTime->utilizationTXPercent())}, jsonObjAirtime["channel_utilization"] = new JSONValue(airTime->channelUtilizationPercent());
{"seconds_since_boot", Json(int(airTime->getSecondsSinceBoot()))}, jsonObjAirtime["utilization_tx"] = new JSONValue(airTime->utilizationTXPercent());
{"seconds_per_period", Json(int(airTime->getSecondsPerPeriod()))}, jsonObjAirtime["seconds_since_boot"] = new JSONValue(int(airTime->getSecondsSinceBoot()));
{"periods_to_log", Json(airTime->getPeriodsToLog())}, jsonObjAirtime["seconds_per_period"] = new JSONValue(int(airTime->getSecondsPerPeriod()));
}; jsonObjAirtime["periods_to_log"] = new JSONValue(airTime->getPeriodsToLog());
// data->wifi // data->wifi
String ipStr = String(WiFi.localIP().toString()); JSONObject jsonObjWifi;
jsonObjWifi["rssi"] = new JSONValue(WiFi.RSSI());
Json jsonObjWifi = Json::object{{"rssi", String(WiFi.RSSI())}, {"ip", ipStr.c_str()}}; jsonObjWifi["ip"] = new JSONValue(WiFi.localIP().toString().c_str());
// data->memory // data->memory
Json jsonObjMemory = Json::object{{"heap_total", Json(int(ESP.getHeapSize()))}, JSONObject jsonObjMemory;
{"heap_free", Json(int(ESP.getFreeHeap()))}, jsonObjMemory["heap_total"] = new JSONValue((int)ESP.getHeapSize());
{"psram_total", Json(int(ESP.getPsramSize()))}, jsonObjMemory["heap_free"] = new JSONValue((int)ESP.getFreeHeap());
{"psram_free", Json(int(ESP.getFreePsram()))}, jsonObjMemory["psram_total"] = new JSONValue((int)ESP.getPsramSize());
{"fs_total", String(FSCom.totalBytes()).c_str()}, jsonObjMemory["psram_free"] = new JSONValue((int)ESP.getFreePsram());
{"fs_used", String(FSCom.usedBytes()).c_str()}, jsonObjMemory["fs_total"] = new JSONValue((int)FSCom.totalBytes());
{"fs_free", String(FSCom.totalBytes() - FSCom.usedBytes()).c_str()}}; jsonObjMemory["fs_used"] = new JSONValue((int)FSCom.usedBytes());
jsonObjMemory["fs_free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));
// data->power // data->power
Json jsonObjPower = Json::object{{"battery_percent", Json(powerStatus->getBatteryChargePercent())}, JSONObject jsonObjPower;
{"battery_voltage_mv", Json(powerStatus->getBatteryVoltageMv())}, jsonObjPower["battery_percent"] = new JSONValue(powerStatus->getBatteryChargePercent());
{"has_battery", BoolToString(powerStatus->getHasBattery())}, jsonObjPower["battery_voltage_mv"] = new JSONValue(powerStatus->getBatteryVoltageMv());
{"has_usb", BoolToString(powerStatus->getHasUSB())}, jsonObjPower["has_battery"] = new JSONValue(BoolToString(powerStatus->getHasBattery()));
{"is_charging", BoolToString(powerStatus->getIsCharging())}}; jsonObjPower["has_usb"] = new JSONValue(BoolToString(powerStatus->getHasUSB()));
jsonObjPower["is_charging"] = new JSONValue(BoolToString(powerStatus->getIsCharging()));
// data->device // data->device
Json jsonObjDevice = Json::object{{"reboot_counter", Json(int(myNodeInfo.reboot_count))}}; JSONObject jsonObjDevice;
jsonObjDevice["reboot_counter"] = new JSONValue((int)myNodeInfo.reboot_count);
// data->radio // data->radio
Json jsonObjRadio = Json::object{{"frequency", Json(RadioLibInterface::instance->getFreq())}, JSONObject jsonObjRadio;
{"lora_channel", Json(int(RadioLibInterface::instance->getChannelNum()))}}; jsonObjRadio["frequency"] = new JSONValue(RadioLibInterface::instance->getFreq());
jsonObjRadio["lora_channel"] = new JSONValue((int)RadioLibInterface::instance->getChannelNum());
// collect data to inner data object // collect data to inner data object
Json jsonObjInner = Json::object{{"airtime", jsonObjAirtime}, {"wifi", jsonObjWifi}, {"memory", jsonObjMemory}, JSONObject jsonObjInner;
{"power", jsonObjPower}, {"device", jsonObjDevice}, {"radio", jsonObjRadio}}; jsonObjInner["airtime"] = new JSONValue(jsonObjAirtime);
jsonObjInner["wifi"] = new JSONValue(jsonObjWifi);
jsonObjInner["memory"] = new JSONValue(jsonObjMemory);
jsonObjInner["power"] = new JSONValue(jsonObjPower);
jsonObjInner["device"] = new JSONValue(jsonObjDevice);
jsonObjInner["radio"] = new JSONValue(jsonObjRadio);
// create json output structure // create json output structure
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}}; JSONObject jsonObjOuter;
jsonObjOuter["data"] = new JSONValue(jsonObjInner);
jsonObjOuter["status"] = new JSONValue("ok");
// serialize and write it to the stream // serialize and write it to the stream
std::string jsonStr = jsonObjOuter.dump(); JSONValue *value = new JSONValue(jsonObjOuter);
res->print(jsonStr.c_str()); res->print(value->Stringify().c_str());
delete value;
} }
/* /*
@@ -767,8 +777,6 @@ void handleRestart(HTTPRequest *req, HTTPResponse *res)
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res) void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
{ {
using namespace json11;
res->setHeader("Content-Type", "application/json"); res->setHeader("Content-Type", "application/json");
res->setHeader("Access-Control-Allow-Origin", "*"); res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "POST"); res->setHeader("Access-Control-Allow-Methods", "POST");
@@ -797,15 +805,15 @@ void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
#endif #endif
} }
Json jsonObjOuter = Json::object{{"status", "ok"}}; JSONObject jsonObjOuter;
std::string jsonStr = jsonObjOuter.dump(); jsonObjOuter["status"] = new JSONValue("ok");
res->print(jsonStr.c_str()); JSONValue *value = new JSONValue(jsonObjOuter);
res->print(value->Stringify().c_str());
delete value;
} }
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res) void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
{ {
using namespace json11;
res->setHeader("Content-Type", "application/json"); res->setHeader("Content-Type", "application/json");
res->setHeader("Access-Control-Allow-Origin", "*"); res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "GET"); res->setHeader("Access-Control-Allow-Methods", "GET");
@@ -814,7 +822,7 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
int n = WiFi.scanNetworks(); int n = WiFi.scanNetworks();
// build list of network objects // build list of network objects
std::vector<Json> networkObjs; JSONArray networkObjs;
if (n > 0) { if (n > 0) {
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
char ssidArray[50]; char ssidArray[50];
@@ -823,8 +831,10 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
ssidString.toCharArray(ssidArray, 50); ssidString.toCharArray(ssidArray, 50);
if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) { if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) {
Json thisNetwork = Json::object{{"ssid", ssidArray}, {"rssi", WiFi.RSSI(i)}}; JSONObject thisNetwork;
networkObjs.push_back(thisNetwork); thisNetwork["ssid"] = new JSONValue(ssidArray);
thisNetwork["rssi"] = new JSONValue(WiFi.RSSI(i));
networkObjs.push_back(new JSONValue(thisNetwork));
} }
// Yield some cpu cycles to IP stack. // Yield some cpu cycles to IP stack.
// This is important in case the list is large and it takes us time to return // This is important in case the list is large and it takes us time to return
@@ -834,9 +844,12 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
} }
// build output structure // build output structure
Json jsonObjOuter = Json::object{{"data", networkObjs}, {"status", "ok"}}; JSONObject jsonObjOuter;
jsonObjOuter["data"] = new JSONValue(networkObjs);
jsonObjOuter["status"] = new JSONValue("ok");
// serialize and write it to the stream // serialize and write it to the stream
std::string jsonStr = jsonObjOuter.dump(); JSONValue *value = new JSONValue(jsonObjOuter);
res->print(jsonStr.c_str()); res->print(value->Stringify().c_str());
delete value;
} }

View File

@@ -1,7 +1,7 @@
#include "mesh/http/WiFiAPClient.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h" #include "RTC.h"
#include "concurrency/Periodic.h" #include "concurrency/Periodic.h"
#include "mesh/http/WiFiAPClient.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
@@ -35,33 +35,36 @@ char ourHost[16];
bool APStartupComplete = 0; bool APStartupComplete = 0;
static bool needReconnect = true; // If we create our reconnector, run it once at the beginning unsigned long lastrun_ntp = 0;
bool needReconnect = true; // If we create our reconnector, run it once at the beginning
Periodic *wifiReconnect;
static int32_t reconnectWiFi() static int32_t reconnectWiFi()
{ {
const char *wifiName = config.network.wifi_ssid; const char *wifiName = config.network.wifi_ssid;
const char *wifiPsw = config.network.wifi_psk; const char *wifiPsw = config.network.wifi_psk;
if (config.network.wifi_enabled && needReconnect && !WiFi.isConnected()) { if (config.network.wifi_enabled && needReconnect) {
if (!*wifiPsw) // Treat empty password as no password if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL; wifiPsw = NULL;
if (*wifiName) { needReconnect = false;
needReconnect = false;
// Make sure we clear old connection credentials // Make sure we clear old connection credentials
WiFi.disconnect(false, true); WiFi.disconnect(false, true);
DEBUG_MSG("... Reconnecting to WiFi access point\n"); DEBUG_MSG("Reconnecting to WiFi access point %s\n",wifiName);
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw); WiFi.mode(WIFI_MODE_STA);
} WiFi.begin(wifiName, wifiPsw);
} }
#ifndef DISABLE_NTP #ifndef DISABLE_NTP
if (WiFi.isConnected()) { if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours
DEBUG_MSG("Updating NTP time\n"); DEBUG_MSG("Updating NTP time from %s\n",config.network.ntp_server);
if (timeClient.update()) { if (timeClient.update()) {
DEBUG_MSG("NTP Request Success - Setting RTCQualityNTP if needed\n"); DEBUG_MSG("NTP Request Success - Setting RTCQualityNTP if needed\n");
@@ -70,6 +73,7 @@ static int32_t reconnectWiFi()
tv.tv_usec = 0; tv.tv_usec = 0;
perhapsSetRTC(RTCQualityNTP, &tv); perhapsSetRTC(RTCQualityNTP, &tv);
lastrun_ntp = millis();
} else { } else {
DEBUG_MSG("NTP Update failed\n"); DEBUG_MSG("NTP Update failed\n");
@@ -77,11 +81,13 @@ static int32_t reconnectWiFi()
} }
#endif #endif
return 43200 * 1000; // every 12 hours if (config.network.wifi_enabled && !WiFi.isConnected()) {
return 1000; // check once per second
} else {
return 300000; // every 5 minutes
}
} }
static Periodic *wifiReconnect;
bool isWifiAvailable() bool isWifiAvailable()
{ {
@@ -95,20 +101,10 @@ bool isWifiAvailable()
// Disable WiFi // Disable WiFi
void deinitWifi() void deinitWifi()
{ {
/*
Note from Jm (jm@casler.org - Sept 16, 2020):
A bug in the ESP32 SDK was introduced in Oct 2019 that keeps the WiFi radio from
turning back on after it's shut off. See:
https://github.com/espressif/arduino-esp32/issues/3522
Until then, WiFi should only be allowed when there's no power
saving on the 2.4g transceiver.
*/
DEBUG_MSG("WiFi deinit\n"); DEBUG_MSG("WiFi deinit\n");
if (isWifiAvailable()) { if (isWifiAvailable()) {
WiFi.disconnect(true);
WiFi.mode(WIFI_MODE_NULL); WiFi.mode(WIFI_MODE_NULL);
DEBUG_MSG("WiFi Turned Off\n"); DEBUG_MSG("WiFi Turned Off\n");
// WiFi.printDiag(Serial); // WiFi.printDiag(Serial);
@@ -119,7 +115,7 @@ static void onNetworkConnected()
{ {
if (!APStartupComplete) { if (!APStartupComplete) {
// Start web server // Start web server
DEBUG_MSG("... Starting network services\n"); DEBUG_MSG("Starting network services\n");
// start mdns // start mdns
if (!MDNS.begin("Meshtastic")) { if (!MDNS.begin("Meshtastic")) {
@@ -158,6 +154,8 @@ bool initWifi()
createSSLCert(); createSSLCert();
esp_wifi_set_storage(WIFI_STORAGE_RAM); // Disable flash storage for WiFi credentials
if (!*wifiPsw) // Treat empty password as no password if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL; wifiPsw = NULL;
@@ -169,7 +167,7 @@ bool initWifi()
WiFi.mode(WIFI_MODE_STA); WiFi.mode(WIFI_MODE_STA);
WiFi.setHostname(ourHost); WiFi.setHostname(ourHost);
WiFi.onEvent(WiFiEvent); WiFi.onEvent(WiFiEvent);
WiFi.setAutoReconnect(true); WiFi.setAutoReconnect(false);
WiFi.setSleep(false); WiFi.setSleep(false);
if (config.network.eth_mode == Config_NetworkConfig_EthMode_STATIC && config.network.ipv4_config.ip != 0) { if (config.network.eth_mode == Config_NetworkConfig_EthMode_STATIC && config.network.ipv4_config.ip != 0) {
WiFi.config(config.network.ipv4_config.ip, WiFi.config(config.network.ipv4_config.ip,
@@ -184,7 +182,7 @@ bool initWifi()
WiFi.onEvent( WiFi.onEvent(
[](WiFiEvent_t event, WiFiEventInfo_t info) { [](WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.print("\nWiFi lost connection. Reason: "); Serial.print("WiFi lost connection. Reason: ");
Serial.println(info.wifi_sta_disconnected.reason); Serial.println(info.wifi_sta_disconnected.reason);
/* /*
@@ -211,88 +209,137 @@ bool initWifi()
// Called by the Espressif SDK to // Called by the Espressif SDK to
static void WiFiEvent(WiFiEvent_t event) static void WiFiEvent(WiFiEvent_t event)
{ {
DEBUG_MSG("************ [WiFi-event] event: %d ************\n", event); DEBUG_MSG("WiFi-Event %d: ", event);
switch (event) { switch (event) {
case SYSTEM_EVENT_WIFI_READY: case ARDUINO_EVENT_WIFI_READY:
DEBUG_MSG("WiFi interface ready\n"); DEBUG_MSG("WiFi interface ready\n");
break; break;
case SYSTEM_EVENT_SCAN_DONE: case ARDUINO_EVENT_WIFI_SCAN_DONE:
DEBUG_MSG("Completed scan for access points\n"); DEBUG_MSG("Completed scan for access points\n");
break; break;
case SYSTEM_EVENT_STA_START: case ARDUINO_EVENT_WIFI_STA_START:
DEBUG_MSG("WiFi station started\n"); DEBUG_MSG("WiFi station started\n");
break; break;
case SYSTEM_EVENT_STA_STOP: case ARDUINO_EVENT_WIFI_STA_STOP:
DEBUG_MSG("WiFi station stopped\n"); DEBUG_MSG("WiFi station stopped\n");
break; break;
case SYSTEM_EVENT_STA_CONNECTED: case ARDUINO_EVENT_WIFI_STA_CONNECTED:
DEBUG_MSG("Connected to access point\n"); DEBUG_MSG("Connected to access point\n");
break; break;
case SYSTEM_EVENT_STA_DISCONNECTED: case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
DEBUG_MSG("Disconnected from WiFi access point\n"); DEBUG_MSG("Disconnected from WiFi access point\n");
WiFi.disconnect(false, true);
needReconnect = true; needReconnect = true;
wifiReconnect->setIntervalFromNow(1000);
break; break;
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
DEBUG_MSG("Authentication mode of access point has changed\n"); DEBUG_MSG("Authentication mode of access point has changed\n");
break; break;
case SYSTEM_EVENT_STA_GOT_IP: case ARDUINO_EVENT_WIFI_STA_GOT_IP:
DEBUG_MSG("Obtained IP address: "); DEBUG_MSG("Obtained IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
onNetworkConnected(); onNetworkConnected();
break; break;
case SYSTEM_EVENT_STA_LOST_IP: case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
DEBUG_MSG("Lost IP address and IP address is reset to 0\n"); DEBUG_MSG("Obtained IP6 address: ");
needReconnect = true; Serial.println(WiFi.localIPv6());
break; break;
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS: case ARDUINO_EVENT_WIFI_STA_LOST_IP:
DEBUG_MSG("Lost IP address and IP address is reset to 0\n");
WiFi.disconnect(false, true);
needReconnect = true;
wifiReconnect->setIntervalFromNow(1000);
break;
case ARDUINO_EVENT_WPS_ER_SUCCESS:
DEBUG_MSG("WiFi Protected Setup (WPS): succeeded in enrollee mode\n"); DEBUG_MSG("WiFi Protected Setup (WPS): succeeded in enrollee mode\n");
break; break;
case SYSTEM_EVENT_STA_WPS_ER_FAILED: case ARDUINO_EVENT_WPS_ER_FAILED:
DEBUG_MSG("WiFi Protected Setup (WPS): failed in enrollee mode\n"); DEBUG_MSG("WiFi Protected Setup (WPS): failed in enrollee mode\n");
break; break;
case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT: case ARDUINO_EVENT_WPS_ER_TIMEOUT:
DEBUG_MSG("WiFi Protected Setup (WPS): timeout in enrollee mode\n"); DEBUG_MSG("WiFi Protected Setup (WPS): timeout in enrollee mode\n");
break; break;
case SYSTEM_EVENT_STA_WPS_ER_PIN: case ARDUINO_EVENT_WPS_ER_PIN:
DEBUG_MSG("WiFi Protected Setup (WPS): pin code in enrollee mode\n"); DEBUG_MSG("WiFi Protected Setup (WPS): pin code in enrollee mode\n");
break; break;
case SYSTEM_EVENT_AP_START: case ARDUINO_EVENT_WPS_ER_PBC_OVERLAP:
DEBUG_MSG("WiFi access point started\n"); DEBUG_MSG("WiFi Protected Setup (WPS): push button overlap in enrollee mode\n");
onNetworkConnected();
break; break;
case SYSTEM_EVENT_AP_STOP: case ARDUINO_EVENT_WIFI_AP_START:
DEBUG_MSG("WiFi access point started\n");
break;
case ARDUINO_EVENT_WIFI_AP_STOP:
DEBUG_MSG("WiFi access point stopped\n"); DEBUG_MSG("WiFi access point stopped\n");
break; break;
case SYSTEM_EVENT_AP_STACONNECTED: case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
DEBUG_MSG("Client connected\n"); DEBUG_MSG("Client connected\n");
break; break;
case SYSTEM_EVENT_AP_STADISCONNECTED: case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:
DEBUG_MSG("Client disconnected\n"); DEBUG_MSG("Client disconnected\n");
break; break;
case SYSTEM_EVENT_AP_STAIPASSIGNED: case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED:
DEBUG_MSG("Assigned IP address to client\n"); DEBUG_MSG("Assigned IP address to client\n");
break; break;
case SYSTEM_EVENT_AP_PROBEREQRECVED: case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED:
DEBUG_MSG("Received probe request\n"); DEBUG_MSG("Received probe request\n");
break; break;
case SYSTEM_EVENT_GOT_IP6: case ARDUINO_EVENT_WIFI_AP_GOT_IP6:
DEBUG_MSG("IPv6 is preferred\n"); DEBUG_MSG("IPv6 is preferred\n");
break; break;
case SYSTEM_EVENT_ETH_START: case ARDUINO_EVENT_WIFI_FTM_REPORT:
DEBUG_MSG("Fast Transition Management report\n");
break;
case ARDUINO_EVENT_ETH_START:
DEBUG_MSG("Ethernet started\n"); DEBUG_MSG("Ethernet started\n");
break; break;
case SYSTEM_EVENT_ETH_STOP: case ARDUINO_EVENT_ETH_STOP:
DEBUG_MSG("Ethernet stopped\n"); DEBUG_MSG("Ethernet stopped\n");
break; break;
case SYSTEM_EVENT_ETH_CONNECTED: case ARDUINO_EVENT_ETH_CONNECTED:
DEBUG_MSG("Ethernet connected\n"); DEBUG_MSG("Ethernet connected\n");
break; break;
case SYSTEM_EVENT_ETH_DISCONNECTED: case ARDUINO_EVENT_ETH_DISCONNECTED:
DEBUG_MSG("Ethernet disconnected\n"); DEBUG_MSG("Ethernet disconnected\n");
break; break;
case SYSTEM_EVENT_ETH_GOT_IP: case ARDUINO_EVENT_ETH_GOT_IP:
DEBUG_MSG("Obtained IP address (SYSTEM_EVENT_ETH_GOT_IP)\n"); DEBUG_MSG("Obtained IP address (ARDUINO_EVENT_ETH_GOT_IP)\n");
break;
case ARDUINO_EVENT_ETH_GOT_IP6:
DEBUG_MSG("Obtained IP6 address (ARDUINO_EVENT_ETH_GOT_IP6)\n");
break;
case ARDUINO_EVENT_SC_SCAN_DONE:
DEBUG_MSG("SmartConfig: Scan done\n");
break;
case ARDUINO_EVENT_SC_FOUND_CHANNEL:
DEBUG_MSG("SmartConfig: Found channel\n");
break;
case ARDUINO_EVENT_SC_GOT_SSID_PSWD:
DEBUG_MSG("SmartConfig: Got SSID and password\n");
break;
case ARDUINO_EVENT_SC_SEND_ACK_DONE:
DEBUG_MSG("SmartConfig: Send ACK done\n");
break;
case ARDUINO_EVENT_PROV_INIT:
DEBUG_MSG("Provisioning: Init\n");
break;
case ARDUINO_EVENT_PROV_DEINIT:
DEBUG_MSG("Provisioning: Stopped\n");
break;
case ARDUINO_EVENT_PROV_START:
DEBUG_MSG("Provisioning: Started\n");
break;
case ARDUINO_EVENT_PROV_END:
DEBUG_MSG("Provisioning: End\n");
break;
case ARDUINO_EVENT_PROV_CRED_RECV:
DEBUG_MSG("Provisioning: Credentials received\n");
break;
case ARDUINO_EVENT_PROV_CRED_FAIL:
DEBUG_MSG("Provisioning: Credentials failed\n");
break;
case ARDUINO_EVENT_PROV_CRED_SUCCESS:
DEBUG_MSG("Provisioning: Credentials success\n");
break; break;
default: default:
break; break;

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "configuration.h" #include "configuration.h"
#include "concurrency/Periodic.h"
#include <Arduino.h> #include <Arduino.h>
#include <functional> #include <functional>
@@ -8,6 +9,9 @@
#include <WiFi.h> #include <WiFi.h>
#endif #endif
extern bool needReconnect;
extern concurrency::Periodic *wifiReconnect;
/// @return true if wifi is now in use /// @return true if wifi is now in use
bool initWifi(); bool initWifi();

View File

@@ -13,7 +13,10 @@
#include "unistd.h" #include "unistd.h"
#endif #endif
#define DEFAULT_REBOOT_SECONDS 5
AdminModule *adminModule; AdminModule *adminModule;
bool hasOpenEditTransaction;
/// A special reserved string to indicate strings we can not share with external nodes. We will use this 'reserved' word instead. /// A special reserved string to indicate strings we can not share with external nodes. We will use this 'reserved' word instead.
/// Also, to make setting work correctly, if someone tries to set a string to this reserved value we assume they don't really want /// Also, to make setting work correctly, if someone tries to set a string to this reserved value we assume they don't really want
@@ -109,12 +112,15 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
if (BleOta::getOtaAppVersion().isEmpty()) { if (BleOta::getOtaAppVersion().isEmpty()) {
DEBUG_MSG("No OTA firmware available, scheduling regular reboot in %d seconds\n", s); DEBUG_MSG("No OTA firmware available, scheduling regular reboot in %d seconds\n", s);
screen->startRebootScreen();
}else{ }else{
screen->startFirmwareUpdateScreen();
BleOta::switchToOtaApp(); BleOta::switchToOtaApp();
DEBUG_MSG("Rebooting to OTA in %d seconds\n", s); DEBUG_MSG("Rebooting to OTA in %d seconds\n", s);
} }
#else #else
DEBUG_MSG("Not on ESP32, scheduling regular reboot in %d seconds\n", s); DEBUG_MSG("Not on ESP32, scheduling regular reboot in %d seconds\n", s);
screen->startRebootScreen();
#endif #endif
rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000); rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
break; break;
@@ -133,13 +139,23 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
case AdminMessage_factory_reset_tag: { case AdminMessage_factory_reset_tag: {
DEBUG_MSG("Initiating factory reset\n"); DEBUG_MSG("Initiating factory reset\n");
nodeDB.factoryReset(); nodeDB.factoryReset();
reboot(5); reboot(DEFAULT_REBOOT_SECONDS);
break; break;
} } case AdminMessage_nodedb_reset_tag: {
case AdminMessage_nodedb_reset_tag: {
DEBUG_MSG("Initiating node-db reset\n"); DEBUG_MSG("Initiating node-db reset\n");
nodeDB.resetNodes(); nodeDB.resetNodes();
reboot(5); reboot(DEFAULT_REBOOT_SECONDS);
break;
}
case AdminMessage_begin_edit_settings_tag: {
DEBUG_MSG("Beginning transaction for editing settings\n");
hasOpenEditTransaction = true;
break;
}
case AdminMessage_commit_edit_settings_tag: {
DEBUG_MSG("Committing transaction for edited settings\n");
hasOpenEditTransaction = false;
saveChanges(SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
break; break;
} }
#ifdef ARCH_PORTDUINO #ifdef ARCH_PORTDUINO
@@ -163,6 +179,12 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
} }
break; break;
} }
// If asked for a response and it is not yet set, generate an 'ACK' response
if (mp.decoded.want_response && !myReply) {
myReply = allocErrorResponse(Routing_Error_NONE, &mp);
}
return handled; return handled;
} }
@@ -173,6 +195,7 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
void AdminModule::handleSetOwner(const User &o) void AdminModule::handleSetOwner(const User &o)
{ {
int changed = 0; int changed = 0;
bool licensed_changed = false;
if (*o.long_name) { if (*o.long_name) {
changed |= strcmp(owner.long_name, o.long_name); changed |= strcmp(owner.long_name, o.long_name);
@@ -188,13 +211,14 @@ void AdminModule::handleSetOwner(const User &o)
} }
if (owner.is_licensed != o.is_licensed) { if (owner.is_licensed != o.is_licensed) {
changed = 1; changed = 1;
licensed_changed = true;
owner.is_licensed = o.is_licensed; owner.is_licensed = o.is_licensed;
config.lora.override_duty_cycle = owner.is_licensed; // override duty cycle for licensed operators
} }
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
service.reloadOwner(); service.reloadOwner(!hasOpenEditTransaction);
DEBUG_MSG("Rebooting due to owner changes\n"); licensed_changed ? saveChanges(SEGMENT_CONFIG | SEGMENT_DEVICESTATE) : saveChanges(SEGMENT_DEVICESTATE);
reboot(5);
} }
} }
@@ -220,7 +244,7 @@ void AdminModule::handleSetConfig(const Config &c)
config.has_position = true; config.has_position = true;
config.position = c.payload_variant.position; config.position = c.payload_variant.position;
// Save nodedb as well in case we got a fixed position packet // Save nodedb as well in case we got a fixed position packet
nodeDB.saveToDisk(SEGMENT_DEVICESTATE); saveChanges(SEGMENT_DEVICESTATE, false);
break; break;
case Config_power_tag: case Config_power_tag:
DEBUG_MSG("Setting config: Power\n"); DEBUG_MSG("Setting config: Power\n");
@@ -252,9 +276,8 @@ void AdminModule::handleSetConfig(const Config &c)
config.bluetooth = c.payload_variant.bluetooth; config.bluetooth = c.payload_variant.bluetooth;
break; break;
} }
service.reloadConfig(SEGMENT_CONFIG); saveChanges(SEGMENT_CONFIG);
reboot(5);
} }
void AdminModule::handleSetModuleConfig(const ModuleConfig &c) void AdminModule::handleSetModuleConfig(const ModuleConfig &c)
@@ -302,15 +325,14 @@ void AdminModule::handleSetModuleConfig(const ModuleConfig &c)
break; break;
} }
service.reloadConfig(SEGMENT_MODULECONFIG); saveChanges(SEGMENT_MODULECONFIG);
reboot(5);
} }
void AdminModule::handleSetChannel(const Channel &cc) void AdminModule::handleSetChannel(const Channel &cc)
{ {
channels.setChannel(cc); channels.setChannel(cc);
channels.onConfigChanged(); // tell the radios about this change channels.onConfigChanged(); // tell the radios about this change
nodeDB.saveChannelsToDisk(); saveChanges(SEGMENT_CHANNELS, false);
} }
/** /**
@@ -479,6 +501,20 @@ void AdminModule::reboot(int32_t seconds)
rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000); rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000);
} }
void AdminModule::saveChanges(int saveWhat, bool shouldReboot)
{
if (!hasOpenEditTransaction) {
DEBUG_MSG("Saving changes to disk\n");
service.reloadConfig(saveWhat); // Calls saveToDisk among other things
} else {
DEBUG_MSG("Delaying save of changes to disk until the open transaction is committed\n");
}
if (shouldReboot)
{
reboot(DEFAULT_REBOOT_SECONDS);
}
}
AdminModule::AdminModule() : ProtobufModule("Admin", PortNum_ADMIN_APP, AdminMessage_fields) AdminModule::AdminModule() : ProtobufModule("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
{ {
// restrict to the admin channel for rx // restrict to the admin channel for rx

View File

@@ -2,7 +2,7 @@
#include "ProtobufModule.h" #include "ProtobufModule.h"
/** /**
* Routing module for router control messages * Admin module for admin messages
*/ */
class AdminModule : public ProtobufModule<AdminMessage> class AdminModule : public ProtobufModule<AdminMessage>
{ {
@@ -20,6 +20,9 @@ class AdminModule : public ProtobufModule<AdminMessage>
virtual bool handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *p) override; virtual bool handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *p) override;
private: private:
bool hasOpenEditTransaction = false;
void saveChanges(int saveWhat, bool shouldReboot = true);
/** /**
* Getters * Getters
*/ */

View File

@@ -176,7 +176,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
DEBUG_MSG("Canned message event Matrix key pressed\n"); DEBUG_MSG("Canned message event Matrix key pressed\n");
// this will send the text immediately on matrix press // this will send the text immediately on matrix press
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_SELECT; this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_SELECT;
this->payload = event->kbchar; this->payload = MATRIXKEY;
this->currentMessageIndex = event->kbchar -1; this->currentMessageIndex = event->kbchar -1;
this->lastTouchMillis = millis(); this->lastTouchMillis = millis();
validEvent = true; validEvent = true;
@@ -246,7 +246,12 @@ int32_t CannedMessageModule::runOnce()
} }
} else { } else {
if ((this->messagesCount > this->currentMessageIndex) && (strlen(this->messages[this->currentMessageIndex]) > 0)) { if ((this->messagesCount > this->currentMessageIndex) && (strlen(this->messages[this->currentMessageIndex]) > 0)) {
sendText(NODENUM_BROADCAST, this->messages[this->currentMessageIndex], true); if(strcmp (this->messages[this->currentMessageIndex], "~") == 0) {
powerFSM.trigger(EVENT_PRESS);
return INT32_MAX;
} else {
sendText(NODENUM_BROADCAST, this->messages[this->currentMessageIndex], true);
}
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE; this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
} else { } else {
DEBUG_MSG("Reset message is empty.\n"); DEBUG_MSG("Reset message is empty.\n");
@@ -446,11 +451,15 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
if (this->destSelect) { if (this->destSelect) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK); display->setColor(BLACK);
display->drawStringf(1 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
} }
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest)); display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
// used chars right aligned // used chars right aligned
sprintf(buffer, "%d left", Constants_DATA_PAYLOAD_LEN - this->freetext.length()); sprintf(buffer, "%d left", Constants_DATA_PAYLOAD_LEN - this->freetext.length());
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer); display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer);
if (this->destSelect) {
display->drawString(x + display->getWidth() - display->getStringWidth(buffer) - 1, y + 0, buffer);
}
display->setColor(WHITE); display->setColor(WHITE);
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor)); display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor));
} else { } else {

View File

@@ -76,7 +76,7 @@ int32_t ExternalNotificationModule::runOnce()
// moduleConfig.external_notification.output_ms = 1000; // moduleConfig.external_notification.output_ms = 1000;
// moduleConfig.external_notification.output = 13; // moduleConfig.external_notification.output = 13;
if (externalCurrentState) { if (externalCurrentState && !moduleConfig.external_notification.use_pwm) {
// If the output is turned on, turn it back off after the given period of time. // If the output is turned on, turn it back off after the given period of time.
if (externalTurnedOn + (moduleConfig.external_notification.output_ms if (externalTurnedOn + (moduleConfig.external_notification.output_ms
@@ -84,13 +84,13 @@ int32_t ExternalNotificationModule::runOnce()
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) < : EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) { millis()) {
DEBUG_MSG("Turning off external notification\n"); DEBUG_MSG("Turning off external notification\n");
if (output != PIN_BUZZER) { setExternalOff();
setExternalOff();
}
} }
} }
if (moduleConfig.external_notification.use_pwm)
return (25); return INT32_MAX; // we don't need this thread here...
else
return 25;
} }
void ExternalNotificationModule::setExternalOn() void ExternalNotificationModule::setExternalOn()
@@ -129,11 +129,6 @@ ExternalNotificationModule::ExternalNotificationModule()
// moduleConfig.external_notification.output_ms = 1000; // moduleConfig.external_notification.output_ms = 1000;
// moduleConfig.external_notification.output = 13; // moduleConfig.external_notification.output = 13;
if (moduleConfig.external_notification.alert_message) {
// restrict to the gpio channel for rx
boundChannel = Channels::gpioChannel;
}
if (moduleConfig.external_notification.enabled) { if (moduleConfig.external_notification.enabled) {
DEBUG_MSG("Initializing External Notification Module\n"); DEBUG_MSG("Initializing External Notification Module\n");
@@ -142,14 +137,19 @@ ExternalNotificationModule::ExternalNotificationModule()
? moduleConfig.external_notification.output ? moduleConfig.external_notification.output
: EXT_NOTIFICATION_MODULE_OUTPUT; : EXT_NOTIFICATION_MODULE_OUTPUT;
if (output != PIN_BUZZER) { if (!moduleConfig.external_notification.use_pwm) {
// Set the direction of a pin // Set the direction of a pin
DEBUG_MSG("Using Pin %i in digital mode\n", output); DEBUG_MSG("Using Pin %i in digital mode\n", output);
pinMode(output, OUTPUT); pinMode(output, OUTPUT);
// Turn off the pin // Turn off the pin
setExternalOff(); setExternalOff();
} else{ } else {
DEBUG_MSG("Using Pin %i in PWM mode\n", output); config.device.buzzer_gpio = config.device.buzzer_gpio
? config.device.buzzer_gpio
: PIN_BUZZER;
// in PWM Mode we force the buzzer pin if it is set
DEBUG_MSG("Using Pin %i in PWM mode\n", config.device.buzzer_gpio);
} }
} else { } else {
DEBUG_MSG("External Notification Module Disabled\n"); DEBUG_MSG("External Notification Module Disabled\n");
@@ -170,7 +170,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
DEBUG_MSG("externalNotificationModule - Notification Bell\n"); DEBUG_MSG("externalNotificationModule - Notification Bell\n");
for (int i = 0; i < p.payload.size; i++) { for (int i = 0; i < p.payload.size; i++) {
if (p.payload.bytes[i] == ASCII_BELL) { if (p.payload.bytes[i] == ASCII_BELL) {
if (output != PIN_BUZZER) { if (!moduleConfig.external_notification.use_pwm) {
setExternalOn(); setExternalOn();
} else { } else {
playBeep(); playBeep();
@@ -181,7 +181,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
if (moduleConfig.external_notification.alert_message) { if (moduleConfig.external_notification.alert_message) {
DEBUG_MSG("externalNotificationModule - Notification Module\n"); DEBUG_MSG("externalNotificationModule - Notification Module\n");
if (output != PIN_BUZZER) { if (!moduleConfig.external_notification.use_pwm) {
setExternalOn(); setExternalOn();
} else { } else {
playBeep(); playBeep();

View File

@@ -11,6 +11,7 @@
#include "modules/ReplyModule.h" #include "modules/ReplyModule.h"
#include "modules/RoutingModule.h" #include "modules/RoutingModule.h"
#include "modules/TextMessageModule.h" #include "modules/TextMessageModule.h"
#include "modules/TraceRouteModule.h"
#include "modules/WaypointModule.h" #include "modules/WaypointModule.h"
#if HAS_TELEMETRY #if HAS_TELEMETRY
#include "modules/Telemetry/DeviceTelemetry.h" #include "modules/Telemetry/DeviceTelemetry.h"
@@ -19,10 +20,8 @@
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "modules/esp32/RangeTestModule.h" #include "modules/esp32/RangeTestModule.h"
#include "modules/esp32/StoreForwardModule.h" #include "modules/esp32/StoreForwardModule.h"
#ifdef USE_SX1280
#include "modules/esp32/AudioModule.h" #include "modules/esp32/AudioModule.h"
#endif #endif
#endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) #if defined(ARCH_ESP32) || defined(ARCH_NRF52)
#include "modules/ExternalNotificationModule.h" #include "modules/ExternalNotificationModule.h"
#if !defined(TTGO_T_ECHO) #if !defined(TTGO_T_ECHO)
@@ -42,6 +41,7 @@ void setupModules()
positionModule = new PositionModule(); positionModule = new PositionModule();
waypointModule = new WaypointModule(); waypointModule = new WaypointModule();
textMessageModule = new TextMessageModule(); textMessageModule = new TextMessageModule();
traceRouteModule = new TraceRouteModule();
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
// to a global variable. // to a global variable.
@@ -68,9 +68,7 @@ void setupModules()
#endif #endif
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
// Only run on an esp32 based device. // Only run on an esp32 based device.
#ifdef USE_SX1280 audioModule = new AudioModule();
new AudioModule();
#endif
new ExternalNotificationModule(); new ExternalNotificationModule();
storeForwardModule = new StoreForwardModule(); storeForwardModule = new StoreForwardModule();

View File

@@ -82,7 +82,7 @@ SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
int32_t SerialModule::runOnce() int32_t SerialModule::runOnce()
{ {
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) #if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
/* /*
Uncomment the preferences below if you want to use the module Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI. without having to configure it from the PythonAPI or WebUI.
@@ -214,7 +214,6 @@ int32_t SerialModule::runOnce()
MeshPacket *SerialModuleRadio::allocReply() MeshPacket *SerialModuleRadio::allocReply()
{ {
auto reply = allocDataPacket(); // Allocate a packet for sending auto reply = allocDataPacket(); // Allocate a packet for sending
return reply; return reply;
@@ -222,8 +221,12 @@ MeshPacket *SerialModuleRadio::allocReply()
void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies) void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
{ {
Channel *ch = (boundChannel != NULL) ? &channels.getByName(boundChannel) : NULL;
MeshPacket *p = allocReply(); MeshPacket *p = allocReply();
p->to = dest; p->to = dest;
if (ch != NULL) {
p->channel = ch->index;
}
p->decoded.want_response = wantReplies; p->decoded.want_response = wantReplies;
p->want_ack = ACK; p->want_ack = ACK;
@@ -236,7 +239,7 @@ void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp) ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
{ {
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) #if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
if (moduleConfig.serial.enabled) { if (moduleConfig.serial.enabled) {
auto &p = mp.decoded; auto &p = mp.decoded;
@@ -266,7 +269,12 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT || if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) { moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) {
Serial2.printf("%s", p.payload.bytes); Serial2.printf("%s", p.payload.bytes);
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG) {
NodeInfo *node = nodeDB.getNode(getFrom(&mp));
String sender = (node && node->has_user) ? node->user.short_name : "???";
Serial2.println();
Serial2.printf("%s: %s", sender, p.payload.bytes);
Serial2.println();
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) { } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
// TODO this needs to be implemented // TODO this needs to be implemented
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) { } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {

View File

@@ -0,0 +1,86 @@
#include "TraceRouteModule.h"
#include "MeshService.h"
#include "FloodingRouter.h"
TraceRouteModule *traceRouteModule;
bool TraceRouteModule::handleReceivedProtobuf(const MeshPacket &mp, RouteDiscovery *r)
{
// Only handle a response
if (mp.decoded.request_id) {
printRoute(r, mp.to, mp.from);
}
return false; // let it be handled by RoutingModule
}
void TraceRouteModule::updateRoute(MeshPacket* p)
{
auto &incoming = p->decoded;
// Only append an ID for the request (one way)
if (!incoming.request_id) {
RouteDiscovery scratch;
RouteDiscovery *updated = NULL;
memset(&scratch, 0, sizeof(scratch));
pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, RouteDiscovery_fields, &scratch);
updated = &scratch;
appendMyID(updated);
printRoute(updated, p->from, NODENUM_BROADCAST);
// Set updated route to the payload of the to be flooded packet
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), RouteDiscovery_fields, updated);
}
}
void TraceRouteModule::appendMyID(RouteDiscovery* updated)
{
// Length of route array can normally not be exceeded due to the max. hop_limit of 7
if (updated->route_count < sizeof(updated->route)/sizeof(updated->route[0])) {
updated->route[updated->route_count] = myNodeInfo.my_node_num;
updated->route_count += 1;
} else {
DEBUG_MSG("WARNING: Route exceeded maximum hop limit, are you bridging networks?\n");
}
}
void TraceRouteModule::printRoute(RouteDiscovery* r, uint32_t origin, uint32_t dest)
{
DEBUG_MSG("Route traced:\n");
DEBUG_MSG("0x%x --> ", origin);
for (uint8_t i=0; i<r->route_count; i++) {
DEBUG_MSG("0x%x --> ", r->route[i]);
}
if (dest != NODENUM_BROADCAST) DEBUG_MSG("0x%x\n", dest); else DEBUG_MSG("...\n");
}
MeshPacket* TraceRouteModule::allocReply()
{
assert(currentRequest);
// Copy the payload of the current request
auto req = *currentRequest;
auto &p = req.decoded;
RouteDiscovery scratch;
RouteDiscovery *updated = NULL;
memset(&scratch, 0, sizeof(scratch));
pb_decode_from_bytes(p.payload.bytes, p.payload.size, RouteDiscovery_fields, &scratch);
updated = &scratch;
printRoute(updated, req.from, req.to);
// Create a MeshPacket with this payload and set it as the reply
MeshPacket* reply = allocDataProtobuf(*updated);
return reply;
}
TraceRouteModule::TraceRouteModule() : ProtobufModule("traceroute", PortNum_TRACEROUTE_APP, RouteDiscovery_fields) {
ourPortNum = PortNum_TRACEROUTE_APP;
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include "ProtobufModule.h"
/**
* A module that traces the route to a certain destination node
*/
class TraceRouteModule : public ProtobufModule<RouteDiscovery>
{
public:
TraceRouteModule();
// Let FloodingRouter call updateRoute upon rebroadcasting a TraceRoute request
friend class FloodingRouter;
protected:
bool handleReceivedProtobuf(const MeshPacket &mp, RouteDiscovery *r) override;
virtual MeshPacket *allocReply() override;
/* Call before rebroadcasting a RouteDiscovery payload in order to update
the route array containing the IDs of nodes this packet went through */
void updateRoute(MeshPacket* p);
private:
// Call to add your ID to the route array of a RouteDiscovery message
void appendMyID(RouteDiscovery *r);
/* Call to print the route array of a RouteDiscovery message.
Set origin to where the request came from.
Set dest to the ID of its destination, or NODENUM_BROADCAST if it has not yet arrived there. */
void printRoute(RouteDiscovery* r, uint32_t origin, uint32_t dest);
};
extern TraceRouteModule *traceRouteModule;

View File

@@ -1,4 +1,6 @@
#include "configuration.h" #include "configuration.h"
#if defined(ARCH_ESP32)
#include "AudioModule.h" #include "AudioModule.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
@@ -8,6 +10,10 @@
#include <assert.h> #include <assert.h>
#ifdef OLED_RU
#include "graphics/fonts/OLEDDisplayFontsRU.h"
#endif
/* /*
AudioModule AudioModule
A interface to send raw codec2 audio data over the mesh network. Based on the example code from the ESP32_codec2 project. A interface to send raw codec2 audio data over the mesh network. Based on the example code from the ESP32_codec2 project.
@@ -19,200 +25,269 @@
Basic Usage: Basic Usage:
1) Enable the module by setting audio.codec2_enabled to 1. 1) Enable the module by setting audio.codec2_enabled to 1.
2) Set the pins (audio.mic_pin / audio.amp_pin) for your preferred microphone and amplifier GPIO pins. 2) Set the pins for the I2S interface. Recommended on TLora is I2S_WS 13/I2S_SD 15/I2S_SIN 2/I2S_SCK 14
On tbeam, recommend to use: 3) Set audio.bitrate to the desired codec2 rate (CODEC2_3200, CODEC2_2400, CODEC2_1600, CODEC2_1400, CODEC2_1300, CODEC2_1200, CODEC2_700, CODEC2_700B)
audio.mic_chan 7 (GPIO 35)
audio.amp_pin 25 (GPIO 25)
3) Set audio.timeout to the amount of time to wait before we consider
your voice stream as "done".
4) Set audio.bitrate to the desired codec2 rate (CODEC2_3200, CODEC2_2400, CODEC2_1600, CODEC2_1400, CODEC2_1300, CODEC2_1200, CODEC2_700, CODEC2_700B)
KNOWN PROBLEMS KNOWN PROBLEMS
* Until the module is initilized by the startup sequence, the amp_pin pin is in a floating * Half Duplex
state. This may produce a bit of "noise". * Will not work on NRF and the Linux device targets (yet?).
* Will not work on NRF and the Linux device targets.
*/ */
#define AMIC 7
#define AAMP 25
#define PTT_PIN 39
#define AUDIO_MODULE_RX_BUFFER 128
#define AUDIO_MODULE_DATA_MAX Constants_DATA_PAYLOAD_LEN
#define AUDIO_MODULE_MODE 7 // 700B
#define AUDIO_MODULE_ACK 1
#if defined(ARCH_ESP32) && defined(USE_SX1280)
AudioModule *audioModule;
ButterworthFilter hp_filter(240, 8000, ButterworthFilter::ButterworthFilter::Highpass, 1); ButterworthFilter hp_filter(240, 8000, ButterworthFilter::ButterworthFilter::Highpass, 1);
//int16_t 1KHz sine test tone TaskHandle_t codec2HandlerTask;
int16_t Sine1KHz[8] = { -21210 , -30000, -21210, 0 , 21210 , 30000 , 21210, 0 }; AudioModule *audioModule;
int Sine1KHz_index = 0;
uint8_t rx_raw_audio_value = 127; #ifdef ARCH_ESP32
// ESP32 doesn't use that flag
#define YIELD_FROM_ISR(x) portYIELD_FROM_ISR()
#else
#define YIELD_FROM_ISR(x) portYIELD_FROM_ISR(x)
#endif
AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP), concurrency::OSThread("AudioModule") { #if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
audio_fifo.init(); // The screen is bigger so use bigger fonts
} #define FONT_SMALL ArialMT_Plain_16
#define FONT_MEDIUM ArialMT_Plain_24
#define FONT_LARGE ArialMT_Plain_24
#else
#ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU
#else
#define FONT_SMALL ArialMT_Plain_10
#endif
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
#endif
void AudioModule::run_codec2() #define fontHeight(font) ((font)[1] + 1) // height is position 1
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE)
void run_codec2(void* parameter)
{ {
if (state == State::tx) // 4 bytes of header in each frame hex c0 de c2 plus the bitrate
{ memcpy(audioModule->tx_encode_frame,&audioModule->tx_header,sizeof(audioModule->tx_header));
for (int i = 0; i < ADC_BUFFER_SIZE; i++)
speech[i] = (int16_t)hp_filter.Update((float)speech[i]);
codec2_encode(codec2_state, tx_encode_frame + tx_encode_frame_index, speech); DEBUG_MSG("Starting codec2 task\n");
//increment the pointer where the encoded frame must be saved while (true) {
tx_encode_frame_index += 8; uint32_t tcount = ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(10000));
//If it is the 5th time then we have a ready trasnmission frame if (tcount != 0) {
if (tx_encode_frame_index == ENCODE_FRAME_SIZE) if (audioModule->radio_state == RadioState::tx) {
{ for (int i = 0; i < audioModule->adc_buffer_size; i++)
tx_encode_frame_index = 0; audioModule->speech[i] = (int16_t)hp_filter.Update((float)audioModule->speech[i]);
//Transmit it
sendPayload(); codec2_encode(audioModule->codec2, audioModule->tx_encode_frame + audioModule->tx_encode_frame_index, audioModule->speech);
audioModule->tx_encode_frame_index += audioModule->encode_codec_size;
if (audioModule->tx_encode_frame_index == (audioModule->encode_frame_size + sizeof(audioModule->tx_header)))
{
DEBUG_MSG("Sending %d codec2 bytes\n", audioModule->encode_frame_size);
audioModule->sendPayload();
audioModule->tx_encode_frame_index = sizeof(audioModule->tx_header);
}
}
if (audioModule->radio_state == RadioState::rx) {
size_t bytesOut = 0;
if (memcmp(audioModule->rx_encode_frame, &audioModule->tx_header, sizeof(audioModule->tx_header)) == 0) {
for (int i = 4; i < audioModule->rx_encode_frame_index; i += audioModule->encode_codec_size)
{
codec2_decode(audioModule->codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
i2s_write(I2S_PORT, &audioModule->output_buffer, audioModule->adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
}
} else {
// if the buffer header does not match our own codec, make a temp decoding setup.
CODEC2* tmp_codec2 = codec2_create(audioModule->rx_encode_frame[3]);
codec2_set_lpc_post_filter(tmp_codec2, 1, 0, 0.8, 0.2);
int tmp_encode_codec_size = (codec2_bits_per_frame(tmp_codec2) + 7) / 8;
int tmp_adc_buffer_size = codec2_samples_per_frame(tmp_codec2);
for (int i = 4; i < audioModule->rx_encode_frame_index; i += tmp_encode_codec_size)
{
codec2_decode(tmp_codec2, audioModule->output_buffer, audioModule->rx_encode_frame + i);
i2s_write(I2S_PORT, &audioModule->output_buffer, tmp_adc_buffer_size, &bytesOut, pdMS_TO_TICKS(500));
}
codec2_destroy(tmp_codec2);
}
}
} }
} }
if (state == State::rx) //Receiving }
{
//Make a cycle to get each codec2 frame from the received frame AudioModule::AudioModule() : SinglePortModule("AudioModule", PortNum_AUDIO_APP), concurrency::OSThread("AudioModule")
for (int i = 0; i < ENCODE_FRAME_SIZE; i += 8) {
{ // moduleConfig.audio.codec2_enabled = true;
//Decode the codec2 frame // moduleConfig.audio.i2s_ws = 13;
codec2_decode(codec2_state, output_buffer, rx_encode_frame + i); // moduleConfig.audio.i2s_sd = 15;
// moduleConfig.audio.i2s_din = 22;
// Add to the audio buffer the 320 samples resulting of the decode of the codec2 frame. // moduleConfig.audio.i2s_sck = 14;
for (int g = 0; g < ADC_BUFFER_SIZE; g++) // moduleConfig.audio.ptt_pin = 39;
audio_fifo.put(output_buffer[g]);
} if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
DEBUG_MSG("Setting up codec2 in mode %u", (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
codec2 = codec2_create((moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
memcpy(tx_header.magic,c2_magic,sizeof(c2_magic));
tx_header.mode = (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1;
codec2_set_lpc_post_filter(codec2, 1, 0, 0.8, 0.2);
encode_codec_size = (codec2_bits_per_frame(codec2) + 7) / 8;
encode_frame_num = (Constants_DATA_PAYLOAD_LEN - sizeof(tx_header)) / encode_codec_size;
encode_frame_size = encode_frame_num * encode_codec_size; // max 233 bytes + 4 header bytes
adc_buffer_size = codec2_samples_per_frame(codec2);
DEBUG_MSG(" using %d frames of %d bytes for a total payload length of %d bytes\n", encode_frame_num, encode_codec_size, encode_frame_size);
xTaskCreate(&run_codec2, "codec2_task", 30000, NULL, 5, &codec2HandlerTask);
} else {
DEBUG_MSG("Codec2 disabled (AudioModule %d, Region %s, permitted %d)\n", moduleConfig.audio.codec2_enabled, myRegion->name, myRegion->audioPermitted);
} }
state = State::standby;
} }
void AudioModule::handleInterrupt() void AudioModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
audioModule->onTimer(); displayedNodeNum = 0; // Not currently showing a node pane
}
void AudioModule::onTimer() char buffer[50];
{
if (state == State::tx) {
adc_buffer[adc_buffer_index++] = (16 * adc1_get_raw(mic_chan)) - 32768;
//If you want to test with a 1KHz tone, comment the line above and descomment the three lines below display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
// adc_buffer[adc_buffer_index++] = Sine1KHz[Sine1KHz_index++]; display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
// if (Sine1KHz_index >= 8) display->setColor(BLACK);
// Sine1KHz_index = 0; display->drawStringf(0 + x, 0 + y, buffer, "Codec2 Mode %d Audio", (moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE) - 1);
display->setColor(WHITE);
if (adc_buffer_index == ADC_BUFFER_SIZE) { display->setFont(FONT_LARGE);
adc_buffer_index = 0; display->setTextAlignment(TEXT_ALIGN_CENTER);
memcpy((void*)speech, (void*)adc_buffer, 2 * ADC_BUFFER_SIZE); switch (radio_state) {
audioModule->setIntervalFromNow(0); // process buffer immediately case RadioState::tx:
} display->drawString(display->getWidth() / 2 + x, (display->getHeight() - FONT_HEIGHT_SMALL) / 2 + y, "PTT");
} else if (state == State::rx) { break;
default:
int16_t v; display->drawString(display->getWidth() / 2 + x, (display->getHeight() - FONT_HEIGHT_SMALL) / 2 + y, "Receive");
break;
//Get a value from audio_fifo and convert it to 0 - 255 to play it in the ADC
//If none value is available the DAC will play the last one that was read, that's
//why the rx_raw_audio_value variable is a global one.
if (audio_fifo.get(&v))
rx_raw_audio_value = (uint8_t)((v + 32768) / 256);
//Play
dacWrite(moduleConfig.audio.amp_pin ? moduleConfig.audio.amp_pin : AAMP, rx_raw_audio_value);
} }
} }
int32_t AudioModule::runOnce() int32_t AudioModule::runOnce()
{ {
if (moduleConfig.audio.codec2_enabled) { if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
esp_err_t res;
if (firstTime) { if (firstTime) {
// Set up I2S Processor configuration. This will produce 16bit samples at 8 kHz instead of 12 from the ADC
DEBUG_MSG("Initializing I2S SD: %d DIN: %d WS: %d SCK: %d\n", moduleConfig.audio.i2s_sd, moduleConfig.audio.i2s_din, moduleConfig.audio.i2s_ws, moduleConfig.audio.i2s_sck);
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | (moduleConfig.audio.i2s_sd ? I2S_MODE_RX : 0) | (moduleConfig.audio.i2s_din ? I2S_MODE_TX : 0)),
.sample_rate = 8000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S),
.intr_alloc_flags = 0,
.dma_buf_count = 8,
.dma_buf_len = adc_buffer_size, // 320 * 2 bytes
.use_apll = false,
.tx_desc_auto_clear = true,
.fixed_mclk = 0
};
res = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
if(res != ESP_OK)
DEBUG_MSG("Failed to install I2S driver: %d\n", res);
DEBUG_MSG("Initializing ADC on Channel %u\n", moduleConfig.audio.mic_chan ? moduleConfig.audio.mic_chan : AMIC); const i2s_pin_config_t pin_config = {
.bck_io_num = moduleConfig.audio.i2s_sck,
.ws_io_num = moduleConfig.audio.i2s_ws,
.data_out_num = moduleConfig.audio.i2s_din ? moduleConfig.audio.i2s_din : I2S_PIN_NO_CHANGE,
.data_in_num = moduleConfig.audio.i2s_sd ? moduleConfig.audio.i2s_sd : I2S_PIN_NO_CHANGE
};
res = i2s_set_pin(I2S_PORT, &pin_config);
if(res != ESP_OK)
DEBUG_MSG("Failed to set I2S pin config: %d\n", res);
mic_chan = moduleConfig.audio.mic_chan ? (adc1_channel_t)(int)moduleConfig.audio.mic_chan : (adc1_channel_t)AMIC; res = i2s_start(I2S_PORT);
adc1_config_width(ADC_WIDTH_12Bit); if(res != ESP_OK)
adc1_config_channel_atten(mic_chan, ADC_ATTEN_DB_6); DEBUG_MSG("Failed to start I2S: %d\n", res);
// Start a timer at 8kHz to sample the ADC and play the audio on the DAC. radio_state = RadioState::rx;
uint32_t cpufreq = getCpuFrequencyMhz();
switch (cpufreq){
case 160:
adcTimer = timerBegin(3, 1000, true); // 160 MHz / 1000 = 160KHz
break;
case 240:
adcTimer = timerBegin(3, 1500, true); // 240 MHz / 1500 = 160KHz
break;
case 320:
adcTimer = timerBegin(3, 2000, true); // 320 MHz / 2000 = 160KHz
break;
case 80:
default:
adcTimer = timerBegin(3, 500, true); // 80 MHz / 500 = 160KHz
break;
}
timerAttachInterrupt(adcTimer, &AudioModule::handleInterrupt, true);
timerAlarmWrite(adcTimer, 20, true); // Interrupts when counter == 20, 8.000 times a second
timerAlarmEnable(adcTimer);
DEBUG_MSG("Initializing DAC on Pin %u\n", moduleConfig.audio.amp_pin ? moduleConfig.audio.amp_pin : AAMP);
DEBUG_MSG("Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN);
// Configure PTT input // Configure PTT input
pinMode(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN, INPUT_PULLUP); DEBUG_MSG("Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN);
pinMode(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN, INPUT);
state = State::rx; firstTime = false;
DEBUG_MSG("Setting up codec2 in mode %u\n", moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE);
codec2_state = codec2_create(moduleConfig.audio.bitrate ? moduleConfig.audio.bitrate : AUDIO_MODULE_MODE);
codec2_set_lpc_post_filter(codec2_state, 1, 0, 0.8, 0.2);
firstTime = 0;
} else { } else {
// Check if we have a PTT press UIFrameEvent e = {false, true};
if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == LOW) { // Check if PTT is pressed. TODO hook that into Onebutton/Interrupt drive.
// PTT pressed, recording if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == HIGH) {
state = State::tx; if (radio_state == RadioState::rx) {
DEBUG_MSG("PTT pressed, switching to TX\n");
radio_state = RadioState::tx;
e.frameChanged = true;
this->notifyObservers(&e);
}
} else {
if (radio_state == RadioState::tx) {
DEBUG_MSG("PTT released, switching to RX\n");
if (tx_encode_frame_index > sizeof(tx_header)) {
// Send the incomplete frame
DEBUG_MSG("Sending %d codec2 bytes (incomplete)\n", tx_encode_frame_index);
sendPayload();
}
tx_encode_frame_index = sizeof(tx_header);
radio_state = RadioState::rx;
e.frameChanged = true;
this->notifyObservers(&e);
}
} }
if (state != State::standby) { if (radio_state == RadioState::tx) {
run_codec2(); // Get I2S data from the microphone and place in data buffer
size_t bytesIn = 0;
res = i2s_read(I2S_PORT, adc_buffer + adc_buffer_index, adc_buffer_size - adc_buffer_index, &bytesIn, pdMS_TO_TICKS(40)); // wait 40ms for audio to arrive.
if (res == ESP_OK) {
adc_buffer_index += bytesIn;
if (adc_buffer_index == adc_buffer_size) {
adc_buffer_index = 0;
memcpy((void*)speech, (void*)adc_buffer, 2 * adc_buffer_size);
// Notify run_codec2 task that the buffer is ready.
radio_state = RadioState::tx;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(codec2HandlerTask, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE)
YIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
} }
} }
return 100; return 100;
} else { } else {
DEBUG_MSG("Audio Module Disabled\n"); DEBUG_MSG("Audio Module Disabled\n");
return INT32_MAX; return INT32_MAX;
} }
} }
MeshPacket *AudioModule::allocReply() MeshPacket *AudioModule::allocReply()
{ {
auto reply = allocDataPacket();
auto reply = allocDataPacket(); // Allocate a packet for sending
return reply; return reply;
} }
bool AudioModule::shouldDraw()
{
if (!moduleConfig.audio.codec2_enabled) {
return false;
}
return (radio_state == RadioState::tx);
}
void AudioModule::sendPayload(NodeNum dest, bool wantReplies) void AudioModule::sendPayload(NodeNum dest, bool wantReplies)
{ {
MeshPacket *p = allocReply(); MeshPacket *p = allocReply();
p->to = dest; p->to = dest;
p->decoded.want_response = wantReplies; p->decoded.want_response = wantReplies;
p->want_ack = AUDIO_MODULE_ACK; p->want_ack = false; // Audio is shoot&forget. No need to wait for ACKs.
p->priority = MeshPacket_Priority_MAX; // Audio is important, because realtime
p->decoded.payload.size = ENCODE_FRAME_SIZE; p->decoded.payload.size = tx_encode_frame_index;
memcpy(p->decoded.payload.bytes, tx_encode_frame, p->decoded.payload.size); memcpy(p->decoded.payload.bytes, tx_encode_frame, p->decoded.payload.size);
service.sendToMesh(p); service.sendToMesh(p);
@@ -220,17 +295,17 @@ void AudioModule::sendPayload(NodeNum dest, bool wantReplies)
ProcessMessage AudioModule::handleReceived(const MeshPacket &mp) ProcessMessage AudioModule::handleReceived(const MeshPacket &mp)
{ {
if (moduleConfig.audio.codec2_enabled) { if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
auto &p = mp.decoded; auto &p = mp.decoded;
if (getFrom(&mp) != nodeDB.getNodeNum()) { if (getFrom(&mp) != nodeDB.getNodeNum()) {
if (p.payload.size == ENCODE_FRAME_SIZE) { memcpy(rx_encode_frame, p.payload.bytes, p.payload.size);
memcpy(rx_encode_frame, p.payload.bytes, p.payload.size); radio_state = RadioState::rx;
state = State::rx; rx_encode_frame_index = p.payload.size;
audioModule->setIntervalFromNow(0); // Notify run_codec2 task that the buffer is ready.
run_codec2(); BaseType_t xHigherPriorityTaskWoken = pdFALSE;
} else { vTaskNotifyGiveFromISR(codec2HandlerTask, &xHigherPriorityTaskWoken);
DEBUG_MSG("Invalid payload size %u != %u\n", p.payload.size, ENCODE_FRAME_SIZE); if (xHigherPriorityTaskWoken == pdTRUE)
} YIELD_FROM_ISR(xHigherPriorityTaskWoken);
} }
} }

View File

@@ -1,68 +1,87 @@
#pragma once #pragma once
#include "SinglePortModule.h" #include "SinglePortModule.h"
#include "concurrency/OSThread.h" #include "concurrency/NotifiedWorkerThread.h"
#include "configuration.h" #include "configuration.h"
#if defined(ARCH_ESP32)
#include "NodeDB.h" #include "NodeDB.h"
#include <Arduino.h> #include <Arduino.h>
#include <driver/adc.h> #include <driver/i2s.h>
#include <functional> #include <functional>
#if defined(ARCH_ESP32) && defined(USE_SX1280)
#include <codec2.h> #include <codec2.h>
#include <ButterworthFilter.h> #include <ButterworthFilter.h>
#include <FastAudioFIFO.h> #include <OLEDDisplay.h>
#endif #include <OLEDDisplayUi.h>
#define ADC_BUFFER_SIZE 320 // 40ms of voice in 8KHz sampling frequency enum RadioState { standby, rx, tx };
#define ENCODE_FRAME_SIZE 40 // 5 codec2 frames of 8 bytes each
class AudioModule : public SinglePortModule, private concurrency::OSThread const char c2_magic[3] = {0xc0, 0xde, 0xc2}; // Magic number for codec2 header
struct c2_header {
char magic[3];
char mode;
};
#define ADC_BUFFER_SIZE_MAX 320
#define PTT_PIN 39
#define I2S_PORT I2S_NUM_0
#define AUDIO_MODULE_RX_BUFFER 128
#define AUDIO_MODULE_MODE ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700
class AudioModule : public SinglePortModule, public Observable<const UIFrameEvent *>, private concurrency::OSThread
{ {
#if defined(ARCH_ESP32) && defined(USE_SX1280)
bool firstTime = 1;
hw_timer_t* adcTimer = NULL;
uint16_t adc_buffer[ADC_BUFFER_SIZE] = {};
int16_t speech[ADC_BUFFER_SIZE] = {};
int16_t output_buffer[ADC_BUFFER_SIZE] = {};
unsigned char rx_encode_frame[ENCODE_FRAME_SIZE] = {};
unsigned char tx_encode_frame[ENCODE_FRAME_SIZE] = {};
int tx_encode_frame_index = 0;
FastAudioFIFO audio_fifo;
uint16_t adc_buffer_index = 0;
adc1_channel_t mic_chan = (adc1_channel_t)0;
struct CODEC2* codec2_state = NULL;
enum State
{
standby, rx, tx
};
volatile State state = State::tx;
public: public:
unsigned char rx_encode_frame[Constants_DATA_PAYLOAD_LEN] = {};
unsigned char tx_encode_frame[Constants_DATA_PAYLOAD_LEN] = {};
c2_header tx_header = {};
int16_t speech[ADC_BUFFER_SIZE_MAX] = {};
int16_t output_buffer[ADC_BUFFER_SIZE_MAX] = {};
uint16_t adc_buffer[ADC_BUFFER_SIZE_MAX] = {};
int adc_buffer_size = 0;
uint16_t adc_buffer_index = 0;
int tx_encode_frame_index = sizeof(c2_header); // leave room for header
int rx_encode_frame_index = 0;
int encode_codec_size = 0;
int encode_frame_size = 0;
volatile RadioState radio_state = RadioState::rx;
struct CODEC2* codec2 = NULL;
// int16_t sample;
AudioModule(); AudioModule();
bool shouldDraw();
/** /**
* Send our payload into the mesh * Send our payload into the mesh
*/ */
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
protected: protected:
int encode_frame_num = 0;
bool firstTime = true;
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
static void handleInterrupt();
void onTimer();
void run_codec2();
virtual MeshPacket *allocReply() override; virtual MeshPacket *allocReply() override;
virtual bool wantUIFrame() override { return this->shouldDraw(); }
virtual Observable<const UIFrameEvent *>* getUIFrameObservable() override { return this; }
#if !HAS_SCREEN
void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
#else
virtual void drawFrame(
OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
#endif
/** Called to handle a particular incoming message /** Called to handle a particular incoming message
* @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it * @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
*/ */
virtual ProcessMessage handleReceived(const MeshPacket &mp) override; virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
#endif
}; };
extern AudioModule *audioModule; extern AudioModule *audioModule;
#endif

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