mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-05 17:40:51 +00:00
Compare commits
736 Commits
v2.0.15.aa
...
v2.2.3.282
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
282cc0b16a | ||
|
|
4ab67f3668 | ||
|
|
312028b161 | ||
|
|
ecd48db69c | ||
|
|
03dc36ea12 | ||
|
|
c2ae38405e | ||
|
|
2a1d8c40b4 | ||
|
|
e2441c425a | ||
|
|
00ffe73ebd | ||
|
|
3355019de3 | ||
|
|
5bb207d88b | ||
|
|
5453e4d123 | ||
|
|
7f1b58a222 | ||
|
|
39357b2686 | ||
|
|
d6b629ae04 | ||
|
|
7b1aeb60cd | ||
|
|
5c7c1cd253 | ||
|
|
8cfe130df3 | ||
|
|
feef86942d | ||
|
|
5f3a8b4924 | ||
|
|
0fcaaf39b0 | ||
|
|
a55eac5c20 | ||
|
|
b47c9c165a | ||
|
|
ecceb10910 | ||
|
|
6fc76103a0 | ||
|
|
f35c7be917 | ||
|
|
364364263b | ||
|
|
ef957bfac5 | ||
|
|
5d78795065 | ||
|
|
2dbdda204f | ||
|
|
4767bd5497 | ||
|
|
05efd68097 | ||
|
|
a90eef432f | ||
|
|
929b8f6209 | ||
|
|
5d76771fab | ||
|
|
91eb64d7b7 | ||
|
|
03fe4c629a | ||
|
|
144dfe9805 | ||
|
|
18899fd168 | ||
|
|
fcfd83bc89 | ||
|
|
a3d2b6166c | ||
|
|
fb5f2e48a5 | ||
|
|
d29c975e3c | ||
|
|
c44986127e | ||
|
|
6e0b6684ee | ||
|
|
84ddfea491 | ||
|
|
3d6fb13f9a | ||
|
|
54c48329c8 | ||
|
|
ede31a2080 | ||
|
|
9470d4694b | ||
|
|
2074c76780 | ||
|
|
9f6584bd67 | ||
|
|
dd69de9f32 | ||
|
|
616553ed72 | ||
|
|
1986267d65 | ||
|
|
1d0ac2caf7 | ||
|
|
746d7268a2 | ||
|
|
9a7777dbdb | ||
|
|
0fe99b0caa | ||
|
|
f9798b7dda | ||
|
|
23fb377fd7 | ||
|
|
4808a5c57f | ||
|
|
d25c368985 | ||
|
|
a5f3dea40b | ||
|
|
f026c3308c | ||
|
|
ed4e7a4cee | ||
|
|
95f67d70ea | ||
|
|
e3260c1d19 | ||
|
|
98f3be0665 | ||
|
|
dc31024764 | ||
|
|
5bbcb40f7a | ||
|
|
8218a729e0 | ||
|
|
cbc3e605dd | ||
|
|
94c41a4fed | ||
|
|
1afe9f75bd | ||
|
|
402f8ba524 | ||
|
|
04bbdc6b8a | ||
|
|
0084c0881d | ||
|
|
8552cc44b9 | ||
|
|
684cce7640 | ||
|
|
114eb0c952 | ||
|
|
bed2bfa074 | ||
|
|
0aef8703b6 | ||
|
|
f5d323fdd3 | ||
|
|
568cc259af | ||
|
|
42039e27e7 | ||
|
|
400b71c152 | ||
|
|
b1f6ff1280 | ||
|
|
cfe5c7f31d | ||
|
|
4e54bec525 | ||
|
|
e0bf15b80e | ||
|
|
26264fd908 | ||
|
|
794948d7e4 | ||
|
|
e9cbe54eca | ||
|
|
641d117106 | ||
|
|
5f38e79b8f | ||
|
|
b238aebe38 | ||
|
|
e05c8e60d9 | ||
|
|
f1bcc300d9 | ||
|
|
06a6a992c2 | ||
|
|
11be856507 | ||
|
|
7fe815a327 | ||
|
|
191a69dd26 | ||
|
|
9eeec6c083 | ||
|
|
c4474a7b99 | ||
|
|
0821cff1c8 | ||
|
|
b799b7bf62 | ||
|
|
90ec8eae6c | ||
|
|
ba172aae32 | ||
|
|
26338b8f2b | ||
|
|
939a359e7e | ||
|
|
5a5af4707c | ||
|
|
ef5e21d3da | ||
|
|
8a49221b7f | ||
|
|
76dc805184 | ||
|
|
297708a50b | ||
|
|
a61a4fad3e | ||
|
|
c66b68b0cc | ||
|
|
97d7a89644 | ||
|
|
04cba45c60 | ||
|
|
502a6596a3 | ||
|
|
5aedd84c7d | ||
|
|
b9c9f0f865 | ||
|
|
ffcc1a0275 | ||
|
|
3d697f8cf4 | ||
|
|
38c9a1ea07 | ||
|
|
0eefd0912f | ||
|
|
0cda8e6087 | ||
|
|
2cf648928a | ||
|
|
3cd7d8d6af | ||
|
|
702a83b525 | ||
|
|
32246850aa | ||
|
|
74650ca276 | ||
|
|
0141bbe772 | ||
|
|
049c587ca2 | ||
|
|
1a28225cd5 | ||
|
|
6bd870c454 | ||
|
|
c782380373 | ||
|
|
4fd756acd8 | ||
|
|
0b509c7e79 | ||
|
|
86af578df9 | ||
|
|
ff11506922 | ||
|
|
f35b422365 | ||
|
|
08f1ac785a | ||
|
|
146ed067a1 | ||
|
|
bdcf17a3f7 | ||
|
|
81edf363d7 | ||
|
|
96c6a20e03 | ||
|
|
3fbe2d771c | ||
|
|
ac9c81f6d1 | ||
|
|
2e7c95a110 | ||
|
|
490abdac96 | ||
|
|
b17436a023 | ||
|
|
b9ae63cb3c | ||
|
|
55701692fd | ||
|
|
470363d294 | ||
|
|
fb21bfe0f5 | ||
|
|
0739bc0cea | ||
|
|
3a24882e76 | ||
|
|
1c74479555 | ||
|
|
084ad1b722 | ||
|
|
2486892e6d | ||
|
|
77efbb3f5d | ||
|
|
eb7025f1b1 | ||
|
|
69beef8310 | ||
|
|
468807466c | ||
|
|
8927cffd64 | ||
|
|
5995c7060d | ||
|
|
541291cc70 | ||
|
|
41b07de5a2 | ||
|
|
4306c32349 | ||
|
|
491fe52841 | ||
|
|
ad5de5a724 | ||
|
|
ab32503601 | ||
|
|
e4e26a819b | ||
|
|
6d97d5dfa2 | ||
|
|
c75965480f | ||
|
|
003047baaf | ||
|
|
4ace59fc18 | ||
|
|
aa0b56e947 | ||
|
|
42d79d012e | ||
|
|
d3e7e45ded | ||
|
|
0cca7751cd | ||
|
|
de53280ffc | ||
|
|
65aafe7ea1 | ||
|
|
6e96216ba3 | ||
|
|
da389eb787 | ||
|
|
d8ad2b3f48 | ||
|
|
97606cd382 | ||
|
|
5c34e36bec | ||
|
|
9c141919f6 | ||
|
|
b9ad274104 | ||
|
|
4ef61f0f15 | ||
|
|
1745722dac | ||
|
|
c120549215 | ||
|
|
7ca2e818df | ||
|
|
f02923435b | ||
|
|
849599cd8e | ||
|
|
eb0a96a79e | ||
|
|
bfc567ad89 | ||
|
|
b665786c77 | ||
|
|
9e2b86b92c | ||
|
|
d0cf70c8b3 | ||
|
|
44a906dd01 | ||
|
|
ccb682bbb8 | ||
|
|
e60a5f1cf2 | ||
|
|
6bdf67c9be | ||
|
|
bbfd62c47e | ||
|
|
e677a02273 | ||
|
|
47168d5063 | ||
|
|
a07e30544d | ||
|
|
5591b9b9f5 | ||
|
|
a2c5b92840 | ||
|
|
9716bd8bec | ||
|
|
685d27f566 | ||
|
|
c2168dd450 | ||
|
|
f71869215d | ||
|
|
66c71250b8 | ||
|
|
81f80546b4 | ||
|
|
44a54278b3 | ||
|
|
5c438ae792 | ||
|
|
194833d77f | ||
|
|
207d421fca | ||
|
|
fb14487f2f | ||
|
|
365a91f3d9 | ||
|
|
cdf44ce7fa | ||
|
|
d70bd23260 | ||
|
|
5edc872c31 | ||
|
|
b42ead4400 | ||
|
|
cd787232ca | ||
|
|
344baf7ffc | ||
|
|
a491ceefcd | ||
|
|
b2704a0082 | ||
|
|
1524c2365f | ||
|
|
9b94701699 | ||
|
|
9d3dc9283c | ||
|
|
61661aed50 | ||
|
|
b1398d0770 | ||
|
|
3a25d6d3b3 | ||
|
|
fd4e9daa7f | ||
|
|
110ec85137 | ||
|
|
99a31c1fad | ||
|
|
b6f7b7fa47 | ||
|
|
113026c372 | ||
|
|
a92a960682 | ||
|
|
3bc82e59dc | ||
|
|
24bb52e83f | ||
|
|
68ef27df8b | ||
|
|
9ddbfc0e3e | ||
|
|
e699427bfc | ||
|
|
696afeef41 | ||
|
|
35ee12cb4c | ||
|
|
94f5c04e19 | ||
|
|
5d2ab65a81 | ||
|
|
f3b7f7251c | ||
|
|
fbcd6743fd | ||
|
|
1b35cc018f | ||
|
|
f18b8328a2 | ||
|
|
d241a010aa | ||
|
|
78af6e2ed8 | ||
|
|
7475c8647c | ||
|
|
f3af3c1c33 | ||
|
|
a583163766 | ||
|
|
e943fc6b8a | ||
|
|
f2cf0ed315 | ||
|
|
59b1adf12f | ||
|
|
1ae77d198d | ||
|
|
2728e86aab | ||
|
|
f8cba0e7f2 | ||
|
|
e5b049d2e2 | ||
|
|
52df85c338 | ||
|
|
2f60bbe5f2 | ||
|
|
0261754269 | ||
|
|
1dfa8f2d9e | ||
|
|
4f0922ec2b | ||
|
|
eb916da8ce | ||
|
|
1b68408f2f | ||
|
|
e6fc2af21f | ||
|
|
a9fed83d9a | ||
|
|
c0979e29ff | ||
|
|
9878ff3836 | ||
|
|
3219ad33ef | ||
|
|
6113a1fb70 | ||
|
|
d11bcda292 | ||
|
|
ae41944a89 | ||
|
|
508cdf6060 | ||
|
|
0009b98996 | ||
|
|
62259583e6 | ||
|
|
c5d87fe581 | ||
|
|
77dace1043 | ||
|
|
e02720b29b | ||
|
|
ffa85ebccd | ||
|
|
f9b2556cd4 | ||
|
|
9c683f4c87 | ||
|
|
cf07d2dbcd | ||
|
|
7711b03bd8 | ||
|
|
c52fddac53 | ||
|
|
b0c3816a8b | ||
|
|
6cdf2817f4 | ||
|
|
f7e1f4cea6 | ||
|
|
75504793e8 | ||
|
|
4029f731c9 | ||
|
|
666a1f3401 | ||
|
|
70dc13a998 | ||
|
|
9841d49fb8 | ||
|
|
28ec4e35ec | ||
|
|
55cef30f93 | ||
|
|
0e15d6a5c2 | ||
|
|
29199e4732 | ||
|
|
6fc061fa43 | ||
|
|
c14b075996 | ||
|
|
6963e43e9f | ||
|
|
1d90096cba | ||
|
|
c1a1b450e3 | ||
|
|
f7041994af | ||
|
|
5037a50059 | ||
|
|
2e915e782b | ||
|
|
e761631d5e | ||
|
|
19a310e196 | ||
|
|
5ec624d9c3 | ||
|
|
b4ff37104a | ||
|
|
81bfd69a41 | ||
|
|
57aaf7f6ee | ||
|
|
9b6ac98ae0 | ||
|
|
e1c4968c58 | ||
|
|
694fd04367 | ||
|
|
cdc8bf44e9 | ||
|
|
09d48f659e | ||
|
|
46e29402a6 | ||
|
|
10f41e376c | ||
|
|
39aa756100 | ||
|
|
17e25babb1 | ||
|
|
7c9d0a022a | ||
|
|
313860c8a4 | ||
|
|
e360c62480 | ||
|
|
973b30fc0b | ||
|
|
a6385a522d | ||
|
|
6aa9e37872 | ||
|
|
5afa92395d | ||
|
|
b6ff80f0b7 | ||
|
|
7ef12c77a8 | ||
|
|
a27d354364 | ||
|
|
6e26f95df9 | ||
|
|
5dfb5172c2 | ||
|
|
e0bb95ca94 | ||
|
|
1621fbb5ab | ||
|
|
ac40f77694 | ||
|
|
9700fa55a3 | ||
|
|
87c59d7d61 | ||
|
|
584615bb4b | ||
|
|
c452c2ab40 | ||
|
|
d43ddc9ec2 | ||
|
|
a76cb94851 | ||
|
|
da75ae21ff | ||
|
|
a30c07e6b4 | ||
|
|
309d4fc7f2 | ||
|
|
a13775bd70 | ||
|
|
b43a5bc4f8 | ||
|
|
ec44ca49fd | ||
|
|
5d41e9fe9d | ||
|
|
7bd836673e | ||
|
|
e0da661632 | ||
|
|
a9ce4338ff | ||
|
|
a284439d7e | ||
|
|
10fac072bb | ||
|
|
d60ccb42da | ||
|
|
3598351689 | ||
|
|
74ed166ff0 | ||
|
|
0afeba0c86 | ||
|
|
ee971e376a | ||
|
|
eeeb7c5080 | ||
|
|
f526c4cc5a | ||
|
|
a9eb19fc62 | ||
|
|
29c13b5c30 | ||
|
|
f0c4c18a79 | ||
|
|
320bf57687 | ||
|
|
4b89f7dfcb | ||
|
|
43cff7adc9 | ||
|
|
d4e42898b1 | ||
|
|
82ab38d3e6 | ||
|
|
aa96ea02c6 | ||
|
|
242f880764 | ||
|
|
de08360271 | ||
|
|
990d418dc8 | ||
|
|
f8db02c622 | ||
|
|
fc8d16bb08 | ||
|
|
af65013e49 | ||
|
|
b1937e03ac | ||
|
|
23e6bc32c0 | ||
|
|
bd1e747fc9 | ||
|
|
3c0817340a | ||
|
|
9a42861766 | ||
|
|
038ff0f6cb | ||
|
|
918b509be8 | ||
|
|
9239698004 | ||
|
|
71479a6b17 | ||
|
|
b4bcae98cd | ||
|
|
294771cb44 | ||
|
|
1398611276 | ||
|
|
fbc3b2beee | ||
|
|
6bf538e26f | ||
|
|
713b5fbe96 | ||
|
|
ed96321406 | ||
|
|
39d8ae64e7 | ||
|
|
3f07251d23 | ||
|
|
657f22d058 | ||
|
|
bf1fbc6c0d | ||
|
|
5679a82195 | ||
|
|
2edc35d34b | ||
|
|
26d18244f0 | ||
|
|
82ba59765c | ||
|
|
7930aa1635 | ||
|
|
c55751964e | ||
|
|
b9b1cce6a5 | ||
|
|
044ef75fef | ||
|
|
9f940139a0 | ||
|
|
fdb09d4fba | ||
|
|
1968f3c45b | ||
|
|
790df42987 | ||
|
|
9a9279dd78 | ||
|
|
1e54a5d45c | ||
|
|
23272daffe | ||
|
|
6e685b0a54 | ||
|
|
1af7e48136 | ||
|
|
eda00b7b9c | ||
|
|
1898fe850e | ||
|
|
15dbe5da97 | ||
|
|
8f736c8ecc | ||
|
|
8a81f190b8 | ||
|
|
1425657a3c | ||
|
|
02041cb605 | ||
|
|
1f130d671b | ||
|
|
d62e56f428 | ||
|
|
5ac24bb33b | ||
|
|
2c259b8464 | ||
|
|
9d6e1ce8e5 | ||
|
|
958d2cf630 | ||
|
|
5cb1f96240 | ||
|
|
78522e750c | ||
|
|
75db8c2d2e | ||
|
|
91be22b341 | ||
|
|
cc64c3d61a | ||
|
|
36b00dba86 | ||
|
|
3bb8cd7613 | ||
|
|
8c68d888c8 | ||
|
|
1f99d4756a | ||
|
|
7bbfa48b5d | ||
|
|
b398f31b64 | ||
|
|
e03a2f8f7f | ||
|
|
d92a003d8e | ||
|
|
8db7316ae1 | ||
|
|
3c2e615650 | ||
|
|
6d202158ba | ||
|
|
c288974b67 | ||
|
|
9b1d461567 | ||
|
|
210e3e09d5 | ||
|
|
0d001423c8 | ||
|
|
a83d5ada86 | ||
|
|
4573db4665 | ||
|
|
d2c72fae00 | ||
|
|
c9686d2f62 | ||
|
|
634251834f | ||
|
|
6d443d2c67 | ||
|
|
9cadc0a16f | ||
|
|
2e3b86608a | ||
|
|
dc2ca9c32b | ||
|
|
e0a6a37bef | ||
|
|
57fc9baafc | ||
|
|
033e988e6f | ||
|
|
fddc49273e | ||
|
|
e737a22120 | ||
|
|
a8f2e3ddbd | ||
|
|
67be6aa53b | ||
|
|
68e17ab905 | ||
|
|
a56403987b | ||
|
|
7acacb3bba | ||
|
|
e6d69e2b67 | ||
|
|
9150c2e568 | ||
|
|
944d5066e9 | ||
|
|
a538a96c90 | ||
|
|
31ef82557f | ||
|
|
9d440b7dba | ||
|
|
267db05d69 | ||
|
|
20bcf310d1 | ||
|
|
331a1afc37 | ||
|
|
321e41a3aa | ||
|
|
3ca1e62b1f | ||
|
|
5044169e8d | ||
|
|
8e197fc35b | ||
|
|
f63505038f | ||
|
|
a95b6aff01 | ||
|
|
b249970a12 | ||
|
|
fe926eedba | ||
|
|
4a0dfb5401 | ||
|
|
4355f51a90 | ||
|
|
ecd67f0a85 | ||
|
|
0940c6462b | ||
|
|
a47364f07b | ||
|
|
eb4ab26e1f | ||
|
|
8c059a8a9e | ||
|
|
7bb281d5c5 | ||
|
|
214feb1f21 | ||
|
|
d17aafa91a | ||
|
|
2fe5eae183 | ||
|
|
9008c75517 | ||
|
|
408c555f0f | ||
|
|
c9ae90f03c | ||
|
|
fbfd0f12b5 | ||
|
|
9650adb616 | ||
|
|
a3f1e53017 | ||
|
|
0243922d64 | ||
|
|
baeb2807a4 | ||
|
|
9a8bfa113d | ||
|
|
82b14fe07c | ||
|
|
fab5e4c5cc | ||
|
|
46fa08dc33 | ||
|
|
48a407bf5c | ||
|
|
05b1fc83bd | ||
|
|
2475debb2a | ||
|
|
568899031d | ||
|
|
f1c457f0c3 | ||
|
|
c8399b7256 | ||
|
|
63005a94fd | ||
|
|
9b4a59f92d | ||
|
|
2472d0947f | ||
|
|
a92b2ec6ca | ||
|
|
548bec026a | ||
|
|
ce882b389a | ||
|
|
25fd9d2d1d | ||
|
|
83a201fe86 | ||
|
|
462ee3d921 | ||
|
|
0104246067 | ||
|
|
3f5c0cb6ac | ||
|
|
fa371bc844 | ||
|
|
090f42f51f | ||
|
|
c2ff6f2f7c | ||
|
|
9fc18c2a19 | ||
|
|
d830398fc5 | ||
|
|
2e80a4ed87 | ||
|
|
e1924f188f | ||
|
|
732caff2b8 | ||
|
|
c60c00ba85 | ||
|
|
83e6cea280 | ||
|
|
f8498ba03f | ||
|
|
f83adf1796 | ||
|
|
73c1c5913b | ||
|
|
fd1c54fd15 | ||
|
|
95bbcd2cb7 | ||
|
|
187f3969c2 | ||
|
|
15458309f8 | ||
|
|
253d133319 | ||
|
|
7264621149 | ||
|
|
27d93c5f66 | ||
|
|
b33632f21a | ||
|
|
89f06d6b40 | ||
|
|
7102fec7b3 | ||
|
|
181832aedd | ||
|
|
4967a16abe | ||
|
|
c39645419a | ||
|
|
6f4ac904a5 | ||
|
|
643237162e | ||
|
|
cef11968eb | ||
|
|
5c72967aa5 | ||
|
|
8aede61adb | ||
|
|
07b90a61e1 | ||
|
|
221a145d2d | ||
|
|
b3fac71a8d | ||
|
|
2e6e0644d4 | ||
|
|
b78e0dce46 | ||
|
|
3ae1fdf661 | ||
|
|
cbfa2dcc0e | ||
|
|
2aabeafefe | ||
|
|
b7895f7038 | ||
|
|
3f4780479f | ||
|
|
5ca3d9169a | ||
|
|
c834252f1c | ||
|
|
16852da8d4 | ||
|
|
2d2633d4cf | ||
|
|
5f28ef6814 | ||
|
|
5cadcd355f | ||
|
|
40d98b9d8d | ||
|
|
0f47584a50 | ||
|
|
dbb827e5e0 | ||
|
|
f95061b965 | ||
|
|
4061870841 | ||
|
|
abf3a5840b | ||
|
|
7063acdda6 | ||
|
|
97c1cf628a | ||
|
|
03f584a5ab | ||
|
|
680550b76c | ||
|
|
a280d7f796 | ||
|
|
09f2ea8938 | ||
|
|
fcbeeac28f | ||
|
|
7100416142 | ||
|
|
e2f5e9206d | ||
|
|
57b8e3732e | ||
|
|
f0d27f896a | ||
|
|
e74b180655 | ||
|
|
88a44eede0 | ||
|
|
83e309f3bf | ||
|
|
dc6f6af7fb | ||
|
|
aaba99f792 | ||
|
|
4375a0101e | ||
|
|
b1677e0312 | ||
|
|
0c240a1dff | ||
|
|
b24376b1fc | ||
|
|
bcaf834853 | ||
|
|
1c3970efab | ||
|
|
79850c6d03 | ||
|
|
440074af62 | ||
|
|
dc23096723 | ||
|
|
3209aeabb8 | ||
|
|
42b496b0db | ||
|
|
a5b99ee5d5 | ||
|
|
4a0c341438 | ||
|
|
afc75b2552 | ||
|
|
9522d4d2f5 | ||
|
|
7ddd8c9930 | ||
|
|
23e1c0b7a8 | ||
|
|
631699bfd7 | ||
|
|
4ac0de21ab | ||
|
|
4ede8ab9de | ||
|
|
b952c35da6 | ||
|
|
a3dbac73fe | ||
|
|
fb611ef986 | ||
|
|
b07904fe77 | ||
|
|
9e1f7c4f56 | ||
|
|
af11c5aa80 | ||
|
|
829318046a | ||
|
|
405430fd96 | ||
|
|
8630e420a7 | ||
|
|
b70af5cc78 | ||
|
|
b9516154d4 | ||
|
|
21443dab05 | ||
|
|
1748db3160 | ||
|
|
d83a0b1818 | ||
|
|
18442816ef | ||
|
|
c28d469fc6 | ||
|
|
d97a09ba1f | ||
|
|
22500a6c34 | ||
|
|
bba4de3ec7 | ||
|
|
1a7991c606 | ||
|
|
490ef459e5 | ||
|
|
40b7d783ed | ||
|
|
6a2583e872 | ||
|
|
3a3451129a | ||
|
|
81d2486cf4 | ||
|
|
9d420f403a | ||
|
|
c82d1de9ce | ||
|
|
9a950afd2a | ||
|
|
ab77772e0c | ||
|
|
ac90c27ae8 | ||
|
|
d6de042783 | ||
|
|
2b15d951cf | ||
|
|
0414ca2dc0 | ||
|
|
7a50934185 | ||
|
|
1fa2ca6a14 | ||
|
|
51521462c4 | ||
|
|
4aaf162700 | ||
|
|
5794a9ae06 | ||
|
|
835e6ab85e | ||
|
|
b97e61d8f8 | ||
|
|
d9031610ab | ||
|
|
a8dd497575 | ||
|
|
971ecd117c | ||
|
|
e8e04d23d7 | ||
|
|
3c6bbff4f9 | ||
|
|
f6c6c2912f | ||
|
|
a13adfb598 | ||
|
|
8734afa7be | ||
|
|
5b75abc6f7 | ||
|
|
e4d455640f | ||
|
|
090d399843 | ||
|
|
c908e61611 | ||
|
|
3dda6e14f7 | ||
|
|
f0f819f403 | ||
|
|
39bb9f21ac | ||
|
|
7750dd2d46 | ||
|
|
d34f6d0f68 | ||
|
|
d02588ad85 | ||
|
|
e4342d9715 | ||
|
|
1f0e64e794 | ||
|
|
e1914dd464 | ||
|
|
04add9b91e | ||
|
|
5e1c39eb0f | ||
|
|
661894f9f9 | ||
|
|
5d1c06b72f | ||
|
|
1407952410 | ||
|
|
860aca9335 | ||
|
|
104ffe36b2 | ||
|
|
5c22901ff1 | ||
|
|
27bd4fa32e | ||
|
|
2be805ce81 | ||
|
|
0a3e512387 | ||
|
|
7b249deb26 | ||
|
|
7aa4e94e45 | ||
|
|
dab2bb3bcc | ||
|
|
afcd7acfab | ||
|
|
0188edb342 | ||
|
|
cd6d8e519b | ||
|
|
02f49d5347 | ||
|
|
2242b68d13 | ||
|
|
a6416f4f08 | ||
|
|
a1d8960f38 | ||
|
|
b1656893ac | ||
|
|
8c0060ecd7 | ||
|
|
0633b2f238 | ||
|
|
ec1358b050 | ||
|
|
cd35e92471 | ||
|
|
76df5265cb | ||
|
|
5f7adf27c3 | ||
|
|
c3d08df18c | ||
|
|
0b84c7c0f3 | ||
|
|
cf5485112b | ||
|
|
43096fb474 | ||
|
|
27b1428d6e | ||
|
|
915404dbe5 | ||
|
|
ab6402e4f4 | ||
|
|
00196ab7e7 | ||
|
|
14831e597c | ||
|
|
c499302092 | ||
|
|
9c7a4aab9e | ||
|
|
7ed39d27e4 | ||
|
|
0e6cfcd48a | ||
|
|
708327240e | ||
|
|
65c0b8e33b | ||
|
|
d876a5254e | ||
|
|
c7937e73a4 | ||
|
|
747292e1e5 | ||
|
|
91575e6241 | ||
|
|
8984989412 | ||
|
|
db729eb707 | ||
|
|
ff029ad752 | ||
|
|
202223236d | ||
|
|
fdf7c3a812 | ||
|
|
f86eef66c8 |
8
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
8
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
@@ -32,16 +32,24 @@ body:
|
|||||||
options:
|
options:
|
||||||
- Not Applicable
|
- Not Applicable
|
||||||
- T-Beam
|
- T-Beam
|
||||||
|
- T-Beam S3
|
||||||
- T-Beam 0.7
|
- T-Beam 0.7
|
||||||
- T-Lora v1
|
- T-Lora v1
|
||||||
- T-Lora v1.3
|
- T-Lora v1.3
|
||||||
- T-Lora v2 1.6
|
- T-Lora v2 1.6
|
||||||
|
- T-Deck
|
||||||
- T-Echo
|
- T-Echo
|
||||||
|
- T-Watch
|
||||||
- Rak4631
|
- Rak4631
|
||||||
- Rak11200
|
- Rak11200
|
||||||
|
- Rak11310
|
||||||
- Heltec v1
|
- Heltec v1
|
||||||
- Heltec v2
|
- Heltec v2
|
||||||
- Heltec v2.1
|
- Heltec v2.1
|
||||||
|
- Heltec V3
|
||||||
|
- Heltec Wireless Paper
|
||||||
|
- Heltec Wireless Tracker
|
||||||
|
- Raspberry Pi Pico (W)
|
||||||
- Relay v1
|
- Relay v1
|
||||||
- Relay v2
|
- Relay v2
|
||||||
- DIY
|
- DIY
|
||||||
|
|||||||
5
.github/pull_request_template.md
vendored
5
.github/pull_request_template.md
vendored
@@ -7,7 +7,8 @@
|
|||||||
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
|
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
|
||||||
- Please do not check in files that don't have real changes
|
- Please do not check in files that don't have real changes
|
||||||
- Please do not reformat lines that you didn't have to change the code on
|
- Please do not reformat lines that you didn't have to change the code on
|
||||||
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor and the 'clang-format' extension,
|
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor along with the ['Trunk Check' extension](https://marketplace.visualstudio.com/items?itemName=trunk.io) (WSL2 is required on windows),
|
||||||
because automatically follows our indentation rules and it's auto reformatting will not cause spurious changes to lines.
|
because it automatically follows our indentation rules and its auto reformatting will not cause spurious changes to lines.
|
||||||
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
|
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
|
||||||
- If your other co-developers have comments on your PR please tweak as needed.
|
- If your other co-developers have comments on your PR please tweak as needed.
|
||||||
|
- Please also enable "Allow edits by maintainers".
|
||||||
|
|||||||
16
.github/workflows/build_esp32.yml
vendored
16
.github/workflows/build_esp32.yml
vendored
@@ -17,11 +17,11 @@ jobs:
|
|||||||
uses: ./.github/actions/setup-base
|
uses: ./.github/actions/setup-base
|
||||||
|
|
||||||
- name: Pull web ui
|
- name: Pull web ui
|
||||||
uses: dsaltares/fetch-gh-release-asset@master
|
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||||
with:
|
with:
|
||||||
repo: "meshtastic/web"
|
repo: meshtastic/web
|
||||||
file: "build.tar"
|
file: build.tar
|
||||||
target: "build.tar"
|
target: build.tar
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Unpack web ui
|
- name: Unpack web ui
|
||||||
@@ -40,11 +40,11 @@ jobs:
|
|||||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||||
|
|
||||||
- name: Pull OTA Firmware
|
- name: Pull OTA Firmware
|
||||||
uses: dsaltares/fetch-gh-release-asset@master
|
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||||
with:
|
with:
|
||||||
repo: "meshtastic/firmware-ota"
|
repo: meshtastic/firmware-ota
|
||||||
file: "firmware.bin"
|
file: firmware.bin
|
||||||
target: "release/bleota.bin"
|
target: release/bleota.bin
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Get release version string
|
- name: Get release version string
|
||||||
|
|||||||
59
.github/workflows/build_esp32_s3.yml
vendored
Normal file
59
.github/workflows/build_esp32_s3.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
name: Build ESP32-S3
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
board:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-esp32-s3:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Build base
|
||||||
|
id: base
|
||||||
|
uses: ./.github/actions/setup-base
|
||||||
|
|
||||||
|
- name: Pull web ui
|
||||||
|
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||||
|
with:
|
||||||
|
repo: meshtastic/web
|
||||||
|
file: build.tar
|
||||||
|
target: build.tar
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Unpack web ui
|
||||||
|
run: |
|
||||||
|
tar -xf build.tar -C data/static
|
||||||
|
rm build.tar
|
||||||
|
- name: Remove debug flags for release
|
||||||
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
|
run: |
|
||||||
|
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
|
||||||
|
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
|
||||||
|
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
|
||||||
|
- name: Build ESP32
|
||||||
|
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||||
|
|
||||||
|
- name: Pull OTA Firmware
|
||||||
|
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||||
|
with:
|
||||||
|
repo: meshtastic/firmware-ota
|
||||||
|
file: firmware-s3.bin
|
||||||
|
target: release/bleota-s3.bin
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
shell: bash
|
||||||
|
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
|
- name: Store binaries as an artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
|
||||||
|
path: |
|
||||||
|
release/*.bin
|
||||||
|
release/*.elf
|
||||||
62
.github/workflows/main_matrix.yml
vendored
62
.github/workflows/main_matrix.yml
vendored
@@ -1,4 +1,7 @@
|
|||||||
name: CI
|
name: CI
|
||||||
|
#concurrency:
|
||||||
|
# group: ${{ github.ref }}
|
||||||
|
# cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||||
on:
|
on:
|
||||||
# # Triggers the workflow on push but only for the master branch
|
# # Triggers the workflow on push but only for the master branch
|
||||||
push:
|
push:
|
||||||
@@ -23,9 +26,9 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- board: rak11200
|
- board: rak11200
|
||||||
- board: tlora-v2-1-1.6
|
- board: tlora-v2-1-1_6
|
||||||
- board: tbeam
|
- board: tbeam
|
||||||
- board: heltec-v2.1
|
- board: heltec-v2_1
|
||||||
- board: meshtastic-diy-v1
|
- board: meshtastic-diy-v1
|
||||||
- board: rak4631
|
- board: rak4631
|
||||||
- board: t-echo
|
- board: t-echo
|
||||||
@@ -33,6 +36,9 @@ jobs:
|
|||||||
- board: m5stack-coreink
|
- board: m5stack-coreink
|
||||||
- board: tbeam-s3-core
|
- board: tbeam-s3-core
|
||||||
- board: tlora-t3s3-v1
|
- board: tlora-t3s3-v1
|
||||||
|
- board: t-watch-s3
|
||||||
|
- board: t-deck
|
||||||
|
#- board: rak11310
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -42,7 +48,8 @@ jobs:
|
|||||||
uses: ./.github/actions/setup-base
|
uses: ./.github/actions/setup-base
|
||||||
|
|
||||||
- name: Trunk Check
|
- name: Trunk Check
|
||||||
uses: trunk-io/trunk-action@v1
|
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||||
|
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
|
||||||
|
|
||||||
- name: Check ${{ matrix.board }}
|
- name: Check ${{ matrix.board }}
|
||||||
run: bin/check-all.sh ${{ matrix.board }}
|
run: bin/check-all.sh ${{ matrix.board }}
|
||||||
@@ -56,24 +63,40 @@ jobs:
|
|||||||
- board: tlora-v2
|
- board: tlora-v2
|
||||||
- board: tlora-v1
|
- board: tlora-v1
|
||||||
- board: tlora_v1_3
|
- board: tlora_v1_3
|
||||||
- board: tlora-v2-1-1.6
|
- board: tlora-v2-1-1_6
|
||||||
- board: tlora-v2-1-1.8
|
- board: tlora-v2-1-1_8
|
||||||
- board: tbeam
|
- board: tbeam
|
||||||
- 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: tbeam0_7
|
||||||
- board: heltec-wsl-v3
|
|
||||||
- board: tbeam0.7
|
|
||||||
- board: meshtastic-diy-v1
|
- board: meshtastic-diy-v1
|
||||||
|
- board: hydra
|
||||||
- board: meshtastic-dr-dev
|
- board: meshtastic-dr-dev
|
||||||
- board: nano-g1
|
- board: nano-g1
|
||||||
- board: station-g1
|
- board: station-g1
|
||||||
- board: m5stack-core
|
- board: m5stack-core
|
||||||
- board: m5stack-coreink
|
- board: m5stack-coreink
|
||||||
|
- board: nano-g1-explorer
|
||||||
|
uses: ./.github/workflows/build_esp32.yml
|
||||||
|
with:
|
||||||
|
board: ${{ matrix.board }}
|
||||||
|
|
||||||
|
build-esp32-s3:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- board: heltec-v3
|
||||||
|
- board: heltec-wsl-v3
|
||||||
|
- board: heltec-wireless-tracker
|
||||||
|
- board: heltec-wireless-paper
|
||||||
- board: tbeam-s3-core
|
- board: tbeam-s3-core
|
||||||
- board: tlora-t3s3-v1
|
- board: tlora-t3s3-v1
|
||||||
uses: ./.github/workflows/build_esp32.yml
|
- board: t-watch-s3
|
||||||
|
- board: t-deck
|
||||||
|
- board: picomputer-s3
|
||||||
|
uses: ./.github/workflows/build_esp32_s3.yml
|
||||||
with:
|
with:
|
||||||
board: ${{ matrix.board }}
|
board: ${{ matrix.board }}
|
||||||
|
|
||||||
@@ -85,9 +108,11 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- board: rak4631
|
- board: rak4631
|
||||||
- board: rak4631_eink
|
- board: rak4631_eink
|
||||||
|
- board: monteops_hw1
|
||||||
- board: t-echo
|
- board: t-echo
|
||||||
- board: pca10059_diy_eink
|
- board: pca10059_diy_eink
|
||||||
- board: feather_diy
|
- board: feather_diy
|
||||||
|
- board: nano-g2-ultra
|
||||||
uses: ./.github/workflows/build_nrf52.yml
|
uses: ./.github/workflows/build_nrf52.yml
|
||||||
with:
|
with:
|
||||||
board: ${{ matrix.board }}
|
board: ${{ matrix.board }}
|
||||||
@@ -99,6 +124,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- board: pico
|
- board: pico
|
||||||
|
- board: rak11310
|
||||||
uses: ./.github/workflows/build_rpi2040.yml
|
uses: ./.github/workflows/build_rpi2040.yml
|
||||||
with:
|
with:
|
||||||
board: ${{ matrix.board }}
|
board: ${{ matrix.board }}
|
||||||
@@ -137,12 +163,14 @@ jobs:
|
|||||||
release/device-*.bat
|
release/device-*.bat
|
||||||
|
|
||||||
- name: Docker login
|
- name: Docker login
|
||||||
|
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: meshtastic
|
username: meshtastic
|
||||||
password: ${{ secrets.DOCKER_TOKEN }}
|
password: ${{ secrets.DOCKER_TOKEN }}
|
||||||
|
|
||||||
- name: Docker setup
|
- name: Docker setup
|
||||||
|
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: Docker build and push tagged versions
|
- name: Docker build and push tagged versions
|
||||||
@@ -155,7 +183,7 @@ jobs:
|
|||||||
tags: meshtastic/device-simulator:${{ steps.version.outputs.version }}
|
tags: meshtastic/device-simulator:${{ steps.version.outputs.version }}
|
||||||
|
|
||||||
- name: Docker build and push
|
- name: Docker build and push
|
||||||
if: github.ref == 'refs/heads/master'
|
if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
@@ -175,7 +203,8 @@ jobs:
|
|||||||
|
|
||||||
gather-artifacts:
|
gather-artifacts:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [build-esp32, build-nrf52, build-native, build-rpi2040]
|
needs:
|
||||||
|
[build-esp32, build-esp32-s3, build-nrf52, build-native, build-rpi2040]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -192,7 +221,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 ./*native*/*device-*.sh ./*native*/*device-*.bat
|
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat
|
||||||
|
|
||||||
- name: Repackage in single firmware zip
|
- name: Repackage in single firmware zip
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
@@ -231,8 +260,9 @@ jobs:
|
|||||||
retention-days: 30
|
retention-days: 30
|
||||||
|
|
||||||
- name: Create request artifacts
|
- name: Create request artifacts
|
||||||
|
continue-on-error: true # FIXME: Why are we getting 502, but things still work?
|
||||||
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
|
||||||
uses: gavv/pull-request-artifacts@v1.0.0
|
uses: gavv/pull-request-artifacts@v1.1.0
|
||||||
with:
|
with:
|
||||||
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
|
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -290,7 +320,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
draft: true
|
draft: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
release_name: Meshtastic Firmware ${{ steps.version.outputs.version }}
|
release_name: Meshtastic Firmware ${{ steps.version.outputs.version }} Alpha
|
||||||
tag_name: v${{ steps.version.outputs.version }}
|
tag_name: v${{ steps.version.outputs.version }}
|
||||||
body: |
|
body: |
|
||||||
Autogenerated by github action, developer should edit as required before publishing...
|
Autogenerated by github action, developer should edit as required before publishing...
|
||||||
|
|||||||
2
.github/workflows/nightly.yml
vendored
2
.github/workflows/nightly.yml
vendored
@@ -14,6 +14,6 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Trunk Check
|
- name: Trunk Check
|
||||||
uses: trunk-io/trunk-action@v1
|
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
|
||||||
with:
|
with:
|
||||||
trunk-token: ${{ secrets.TRUNK_TOKEN }}
|
trunk-token: ${{ secrets.TRUNK_TOKEN }}
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -30,3 +30,4 @@ __pycache__
|
|||||||
venv/
|
venv/
|
||||||
release/
|
release/
|
||||||
.vscode/extensions.json
|
.vscode/extensions.json
|
||||||
|
/compile_commands.json
|
||||||
|
|||||||
1
.trunk/.gitignore
vendored
1
.trunk/.gitignore
vendored
@@ -5,3 +5,4 @@
|
|||||||
plugins
|
plugins
|
||||||
user_trunk.yaml
|
user_trunk.yaml
|
||||||
user.yaml
|
user.yaml
|
||||||
|
tools
|
||||||
|
|||||||
3
.trunk/configs/.flake8
Normal file
3
.trunk/configs/.flake8
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Autoformatter friendly flake8 config (all formatting rules disabled)
|
||||||
|
[flake8]
|
||||||
|
extend-ignore = D1, D2, E1, E2, E3, E501, W1, W2, W3, W5
|
||||||
2
.trunk/configs/.isort.cfg
Normal file
2
.trunk/configs/.isort.cfg
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[settings]
|
||||||
|
profile=black
|
||||||
10
.trunk/configs/.yamllint.yaml
Normal file
10
.trunk/configs/.yamllint.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
rules:
|
||||||
|
quoted-strings:
|
||||||
|
required: only-when-needed
|
||||||
|
extra-allowed: ["{|}"]
|
||||||
|
empty-values:
|
||||||
|
forbid-in-block-mappings: true
|
||||||
|
forbid-in-flow-mappings: true
|
||||||
|
key-duplicates: {}
|
||||||
|
octal-values:
|
||||||
|
forbid-implicit-octal: true
|
||||||
5
.trunk/configs/ruff.toml
Normal file
5
.trunk/configs/ruff.toml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Generic, formatter-friendly config.
|
||||||
|
select = ["B", "D3", "D4", "E", "F"]
|
||||||
|
|
||||||
|
# Never enforce `E501` (line length violations). This should be handled by formatters.
|
||||||
|
ignore = ["E501"]
|
||||||
@@ -1,28 +1,48 @@
|
|||||||
version: 0.1
|
version: 0.1
|
||||||
cli:
|
cli:
|
||||||
version: 1.3.1
|
version: 1.13.0
|
||||||
plugins:
|
plugins:
|
||||||
sources:
|
sources:
|
||||||
- id: trunk
|
- id: trunk
|
||||||
ref: v0.0.8
|
ref: v1.1.1
|
||||||
uri: https://github.com/trunk-io/plugins
|
uri: https://github.com/trunk-io/plugins
|
||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- git-diff-check
|
- bandit@1.7.5
|
||||||
- gitleaks@8.15.2
|
- checkov@2.4.1
|
||||||
- clang-format@14.0.0
|
- terrascan@1.18.3
|
||||||
- prettier@2.8.3
|
- trivy@0.44.1
|
||||||
disabled:
|
- trufflehog@3.48.0
|
||||||
|
- taplo@0.8.1
|
||||||
|
- ruff@0.0.284
|
||||||
|
- yamllint@1.32.0
|
||||||
|
- isort@5.12.0
|
||||||
|
- markdownlint@0.35.0
|
||||||
|
- oxipng@8.0.0
|
||||||
|
- svgo@3.0.2
|
||||||
|
- actionlint@1.6.25
|
||||||
|
- flake8@6.1.0
|
||||||
|
- hadolint@2.12.0
|
||||||
|
- shfmt@3.6.0
|
||||||
- shellcheck@0.9.0
|
- shellcheck@0.9.0
|
||||||
- shfmt@3.5.0
|
- black@23.7.0
|
||||||
|
- git-diff-check
|
||||||
|
- gitleaks@8.17.0
|
||||||
|
- clang-format@16.0.3
|
||||||
|
- prettier@3.0.2
|
||||||
|
disabled:
|
||||||
|
- taplo@0.8.1
|
||||||
|
- shellcheck@0.9.0
|
||||||
|
- shfmt@3.6.0
|
||||||
- oxipng@8.0.0
|
- oxipng@8.0.0
|
||||||
- actionlint@1.6.22
|
- actionlint@1.6.22
|
||||||
- markdownlint@0.33.0
|
- markdownlint@0.35.0
|
||||||
- hadolint@2.12.0
|
- hadolint@2.12.0
|
||||||
- svgo@3.0.2
|
- svgo@3.0.2
|
||||||
runtimes:
|
runtimes:
|
||||||
enabled:
|
enabled:
|
||||||
- go@1.18.3
|
- python@3.10.8
|
||||||
|
- go@1.19.5
|
||||||
- node@18.12.1
|
- node@18.12.1
|
||||||
actions:
|
actions:
|
||||||
disabled:
|
disabled:
|
||||||
|
|||||||
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@@ -6,4 +6,4 @@
|
|||||||
"platformio.platformio-ide",
|
"platformio.platformio-ide",
|
||||||
"trunk.io"
|
"trunk.io"
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.defaultFormatter": "trunk.io"
|
"editor.defaultFormatter": "trunk.io",
|
||||||
|
"trunk.enableWindows": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
; Common settings for ESP targes, mixin with extends = esp32_base
|
; Common settings for ESP targes, mixin with extends = esp32_base
|
||||||
[esp32_base]
|
[esp32_base]
|
||||||
extends = arduino_base
|
extends = arduino_base
|
||||||
platform = platformio/espressif32@^5.2.0
|
platform = platformio/espressif32@^6.3.2
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
|
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
|
||||||
|
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
debug_init_break = tbreak setup
|
debug_init_break = tbreak setup
|
||||||
monitor_filters = esp32_exception_decoder
|
monitor_filters = esp32_exception_decoder
|
||||||
|
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
|
|
||||||
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
|
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
|
||||||
@@ -25,8 +28,10 @@ build_flags =
|
|||||||
-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
|
||||||
|
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120
|
||||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||||
-DDEBUG_HEAP
|
-DSERIAL_BUFFER_SIZE=4096
|
||||||
|
;-DDEBUG_HEAP
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${arduino_base.lib_deps}
|
${arduino_base.lib_deps}
|
||||||
@@ -34,8 +39,9 @@ lib_deps =
|
|||||||
${environmental_base.lib_deps}
|
${environmental_base.lib_deps}
|
||||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
||||||
h2zero/NimBLE-Arduino@^1.4.0
|
h2zero/NimBLE-Arduino@^1.4.0
|
||||||
|
jgromes/RadioLib@^6.1.0
|
||||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||||
caveman99/ESP32 Codec2@^1.0.1
|
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
|
||||||
|
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
segger_rtt
|
segger_rtt
|
||||||
@@ -51,4 +57,4 @@ lib_ignore =
|
|||||||
|
|
||||||
; customize the partition table
|
; customize the partition table
|
||||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||||
board_build.partitions = partition-table.csv
|
board_build.partitions = partition-table.csv
|
||||||
5
arch/esp32/esp32c3.ini
Normal file
5
arch/esp32/esp32c3.ini
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[esp32c3_base]
|
||||||
|
extends = esp32_base
|
||||||
|
|
||||||
|
monitor_speed = 115200
|
||||||
|
monitor_filters = esp32_c3_exception_decoder
|
||||||
@@ -1,47 +1,16 @@
|
|||||||
[esp32s2_base]
|
[esp32s2_base]
|
||||||
extends = arduino_base
|
extends = esp32_base
|
||||||
platform = platformio/espressif32@^5.2.0
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<nimble/>
|
${esp32_base.build_src_filter} -<nimble/>
|
||||||
upload_speed = 961200
|
|
||||||
monitor_speed = 115200
|
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 =
|
build_flags =
|
||||||
${arduino_base.build_flags}
|
${esp32_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
|
-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 =
|
lib_ignore =
|
||||||
segger_rtt
|
${esp32_base.lib_ignore}
|
||||||
ESP32 BLE Arduino
|
NimBLE-Arduino
|
||||||
|
|
||||||
; customize the partition table
|
|
||||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
|
||||||
board_build.partitions = partition-table.csv
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +1,5 @@
|
|||||||
[esp32s3_base]
|
[esp32s3_base]
|
||||||
extends = arduino_base
|
extends = esp32_base
|
||||||
platform = platformio/espressif32@^5.2.0
|
|
||||||
build_src_filter =
|
|
||||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
|
|
||||||
upload_speed = 961200
|
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
debug_init_break = tbreak setup
|
|
||||||
monitor_filters = esp32_exception_decoder
|
|
||||||
board_build.filesystem = littlefs
|
|
||||||
|
|
||||||
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
|
|
||||||
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
|
|
||||||
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
|
|
||||||
build_flags =
|
|
||||||
${arduino_base.build_flags}
|
|
||||||
-Wall
|
|
||||||
-Wextra
|
|
||||||
-Isrc/platform/esp32
|
|
||||||
-std=c++11
|
|
||||||
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG
|
|
||||||
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
|
|
||||||
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
|
|
||||||
-DAXP_DEBUG_PORT=Serial
|
|
||||||
-DCONFIG_BT_NIMBLE_ENABLED
|
|
||||||
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
|
|
||||||
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
|
|
||||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
|
||||||
-DDEBUG_HEAP
|
|
||||||
|
|
||||||
lib_deps =
|
|
||||||
${arduino_base.lib_deps}
|
|
||||||
${networking_base.lib_deps}
|
|
||||||
${environmental_base.lib_deps}
|
|
||||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
|
||||||
h2zero/NimBLE-Arduino@^1.4.0
|
|
||||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
|
||||||
caveman99/ESP32 Codec2@^1.0.1
|
|
||||||
|
|
||||||
lib_ignore =
|
|
||||||
segger_rtt
|
|
||||||
ESP32 BLE Arduino
|
|
||||||
|
|
||||||
; customize the partition table
|
|
||||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
|
||||||
board_build.partitions = partition-table.csv
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
[nrf52_base]
|
[nrf52_base]
|
||||||
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
||||||
platform = platformio/nordicnrf52@^9.4.0
|
platform = platformio/nordicnrf52@^10.1.0
|
||||||
|
|
||||||
extends = arduino_base
|
extends = arduino_base
|
||||||
|
|
||||||
build_type = debug ; I'm debugging with ICE a lot now
|
build_type = debug ; I'm debugging with ICE a lot now
|
||||||
build_flags =
|
build_flags =
|
||||||
${arduino_base.build_flags} -Wno-unused-variable
|
${arduino_base.build_flags}
|
||||||
|
-DSERIAL_BUFFER_SIZE=1024
|
||||||
|
-Wno-unused-variable
|
||||||
-Isrc/platform/nrf52
|
-Isrc/platform/nrf52
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/rp2040> -<mesh/eth/>
|
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/>
|
||||||
|
|
||||||
|
lib_deps=
|
||||||
|
${arduino_base.lib_deps}
|
||||||
|
jgromes/RadioLib@^6.1.0
|
||||||
|
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
BluetoothOTA
|
BluetoothOTA
|
||||||
|
|
||||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
|
||||||
[env:feather_nrf52832]
|
|
||||||
extends = nrf52_base
|
|
||||||
board = adafruit_feather_nrf52832
|
|
||||||
7
arch/nrf52/nrf52832.ini
Normal file
7
arch/nrf52/nrf52832.ini
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[nrf52832_base]
|
||||||
|
extends = nrf52_base
|
||||||
|
|
||||||
|
build_flags = ${nrf52_base.build_flags}
|
||||||
|
|
||||||
|
lib_deps =
|
||||||
|
${nrf52_base.lib_deps}
|
||||||
@@ -1,14 +1,9 @@
|
|||||||
[nrf52840_base]
|
[nrf52840_base]
|
||||||
extends = nrf52_base
|
extends = nrf52_base
|
||||||
|
|
||||||
build_flags = ${nrf52_base.build_flags}
|
build_flags = ${nrf52_base.build_flags}
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${arduino_base.lib_deps}
|
${nrf52_base.lib_deps}
|
||||||
${environmental_base.lib_deps}
|
${environmental_base.lib_deps}
|
||||||
https://github.com/Kongduino/Adafruit_nRFCrypto.git#e31a8825ea3300b163a0a3c1ddd5de34e10e1371
|
https://github.com/Kongduino/Adafruit_nRFCrypto.git#e31a8825ea3300b163a0a3c1ddd5de34e10e1371
|
||||||
|
|
||||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
|
||||||
[env:nrf52840dk]
|
|
||||||
extends = nrf52840_base
|
|
||||||
board = nrf52840_dk
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
; 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
|
platform = https://github.com/meshtastic/platform-native.git#489ff929dca0bb768256ba2de45f95815111490f
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${env.build_src_filter}
|
${env.build_src_filter}
|
||||||
-<platform/esp32/>
|
-<platform/esp32/>
|
||||||
@@ -12,10 +13,18 @@ build_src_filter =
|
|||||||
-<mesh/http/>
|
-<mesh/http/>
|
||||||
-<mesh/eth/>
|
-<mesh/eth/>
|
||||||
-<modules/esp32>
|
-<modules/esp32>
|
||||||
-<modules/Telemetry>
|
-<modules/Telemetry/EnvironmentTelemetry.cpp>
|
||||||
|
-<modules/Telemetry/AirQualityTelemetry.cpp>
|
||||||
|
-<modules/Telemetry/Sensor>
|
||||||
+<../variants/portduino>
|
+<../variants/portduino>
|
||||||
|
|
||||||
lib_deps =
|
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
|
||||||
build_flags = ${arduino_base.build_flags} -Isrc/platform/portduino
|
jgromes/RadioLib@6.1.0
|
||||||
|
|
||||||
|
build_flags =
|
||||||
|
${arduino_base.build_flags}
|
||||||
|
-fPIC
|
||||||
|
-Isrc/platform/portduino
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
; Common settings for rp2040 Processor based targets
|
; Common settings for rp2040 Processor based targets
|
||||||
[rp2040_base]
|
[rp2040_base]
|
||||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#20c7dbfcfe6677c5305fa28ecf5e3870321cb157
|
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#0c33219f53faa035e188925ea1324f472e8b93d2
|
||||||
platform_packages =
|
|
||||||
earlephilhower/toolchain-rp2040-earlephilhower@^5.100300.221223
|
|
||||||
extends = arduino_base
|
extends = arduino_base
|
||||||
|
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.2.2
|
||||||
|
|
||||||
board_build.core = earlephilhower
|
board_build.core = earlephilhower
|
||||||
board_build.filesystem_size = 0.5m
|
board_build.filesystem_size = 0.5m
|
||||||
build_flags =
|
build_flags =
|
||||||
@@ -12,10 +12,13 @@ build_flags =
|
|||||||
-D__PLAT_RP2040__
|
-D__PLAT_RP2040__
|
||||||
# -D _POSIX_THREADS
|
# -D _POSIX_THREADS
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/>
|
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/>
|
||||||
|
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
BluetoothOTA
|
BluetoothOTA
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${arduino_base.lib_deps}
|
${arduino_base.lib_deps}
|
||||||
${environmental_base.lib_deps}
|
${environmental_base.lib_deps}
|
||||||
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
jgromes/RadioLib@^6.1.0
|
||||||
|
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
||||||
@@ -1,18 +1,29 @@
|
|||||||
[stm32wl5e_base]
|
[stm32wl5e_base]
|
||||||
platform = platformio/ststm32@^15.4.1
|
platform_packages = platformio/framework-arduinoststm32 @ https://github.com/stm32duino/Arduino_Core_STM32.git#6e3f9910d0122e82a6c3438507dfac3d2fd80a39
|
||||||
|
platform = ststm32
|
||||||
board = generic_wl5e
|
board = generic_wl5e
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
|
||||||
build_type = debug
|
build_type = debug
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${arduino_base.build_flags}
|
${arduino_base.build_flags}
|
||||||
-Isrc/platform/stm32wl -g
|
-Isrc/platform/stm32wl -g
|
||||||
-DHAL_SUBGHZ_MODULE_ENABLED
|
-DconfigUSE_CMSIS_RTOS_V2=1
|
||||||
# Arduino/PlatformIO framework-arduinoststm32 package does not presently have SUBGHZSPI support
|
-DVECT_TAB_OFFSET=0x08000000
|
||||||
# -DPIN_SPI_MOSI=PINSUBGHZSPIMOSI -DPIN_SPI_MISO=PINSUBGHZSPIMISO -DPIN_SPI_SCK=PINSUBGHZSPISCK
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<mqtt/> -<graphics> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||||
|
|
||||||
|
board_upload.offset_address = 0x08000000
|
||||||
|
upload_protocol = stlink
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
|
jgromes/RadioLib@^6.1.0
|
||||||
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
||||||
lib_ignore =
|
https://github.com/littlefs-project/littlefs.git#v2.5.1
|
||||||
mathertel/OneButton@^2.0.3
|
https://github.com/stm32duino/STM32FreeRTOS.git#10.3.1
|
||||||
|
|
||||||
|
lib_ignore =
|
||||||
|
https://github.com/mathertel/OneButton#2.1.0
|
||||||
@@ -34,7 +34,7 @@ SRCBIN=.pio/build/$1/firmware.bin
|
|||||||
cp $SRCBIN $OUTDIR/$basename-update.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 $1 -t buildfs
|
||||||
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
|
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
|
||||||
cp bin/device-install.* $OUTDIR
|
cp bin/device-install.* $OUTDIR
|
||||||
cp bin/device-update.* $OUTDIR
|
cp bin/device-update.* $OUTDIR
|
||||||
|
|||||||
@@ -4,23 +4,23 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
VERSION=`bin/buildinfo.py long`
|
VERSION=$(bin/buildinfo.py long)
|
||||||
|
|
||||||
# The shell vars the build tool expects to find
|
# The shell vars the build tool expects to find
|
||||||
export APP_VERSION=$VERSION
|
export APP_VERSION=$VERSION
|
||||||
|
|
||||||
if [[ $# -gt 0 ]]; then
|
if [[ $# -gt 0 ]]; then
|
||||||
# can override which environment by passing arg
|
# can override which environment by passing arg
|
||||||
BOARDS="$@"
|
BOARDS="$@"
|
||||||
else
|
else
|
||||||
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631 rak4631_eink rak11200 t-echo pca10059_diy_eink"
|
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631 rak4631_eink rak11200 t-echo pca10059_diy_eink"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "BOARDS:${BOARDS}"
|
echo "BOARDS:${BOARDS}"
|
||||||
|
|
||||||
CHECK=""
|
CHECK=""
|
||||||
for BOARD in $BOARDS; do
|
for BOARD in $BOARDS; do
|
||||||
CHECK="${CHECK} -e ${BOARD}"
|
CHECK="${CHECK} -e ${BOARD}"
|
||||||
done
|
done
|
||||||
|
|
||||||
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt" $CHECK --skip-packages --pattern="src/" --fail-on-defect=low --fail-on-defect=medium --fail-on-defect=high
|
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt" $CHECK --skip-packages --pattern="src/" --fail-on-defect=medium --fail-on-defect=high
|
||||||
|
|||||||
@@ -30,7 +30,13 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
|
|||||||
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
|
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%
|
||||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
|
||||||
|
@REM Account for S3 board's different OTA partition
|
||||||
|
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% IF x%FILENAME:t-deck=%==x%FILENAME% IF x%FILENAME:wireless-paper=%==x%FILENAME% IF x%FILENAME:wireless-tracker=%==x%FILENAME% (
|
||||||
|
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
||||||
|
) else (
|
||||||
|
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
|
||||||
|
)
|
||||||
for %%f in (littlefs-*.bin) do (
|
for %%f in (littlefs-*.bin) do (
|
||||||
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
|
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -49,7 +49,12 @@ 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}
|
||||||
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
# Account for S3 board's different OTA partition
|
||||||
|
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ] && [ ! -z "${FILENAME##*"t-deck"*}" ] && [ ! -z "${FILENAME##*"wireless-paper"*}" ] && [ ! -z "${FILENAME##*"wireless-tracker"*}" ]; then
|
||||||
|
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
||||||
|
else
|
||||||
|
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
|
||||||
|
fi
|
||||||
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
|
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|||||||
38
bin/generate_ci_matrix.py
Executable file
38
bin/generate_ci_matrix.py
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""Generate the CI matrix"""
|
||||||
|
|
||||||
|
import configparser
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
rootdir = "variants/"
|
||||||
|
|
||||||
|
options = sys.argv[1:]
|
||||||
|
|
||||||
|
outlist = []
|
||||||
|
|
||||||
|
if len(options) < 1:
|
||||||
|
print(json.dumps(outlist))
|
||||||
|
exit()
|
||||||
|
|
||||||
|
for subdir, dirs, files in os.walk(rootdir):
|
||||||
|
for file in files:
|
||||||
|
if file == "platformio.ini":
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read(subdir + "/" + file)
|
||||||
|
for c in config.sections():
|
||||||
|
if c.startswith("env:"):
|
||||||
|
section = config[c].name[4:]
|
||||||
|
if "extends" in config[config[c].name]:
|
||||||
|
if config[config[c].name]["extends"] == options[0] + "_base":
|
||||||
|
if "board_level" in config[config[c].name]:
|
||||||
|
if (
|
||||||
|
config[config[c].name]["board_level"] == "extra"
|
||||||
|
) & ("extra" in options):
|
||||||
|
outlist.append(section)
|
||||||
|
else:
|
||||||
|
outlist.append(section)
|
||||||
|
|
||||||
|
print(json.dumps(outlist))
|
||||||
@@ -1,5 +1 @@
|
|||||||
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs ..\protobufs\meshtastic\*.proto
|
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --experimental_allow_proto3_optional --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs ..\protobufs\meshtastic\*.proto
|
||||||
|
|
||||||
@REM cd ../src/mesh/generated/meshtastic
|
|
||||||
@REM sed -i 's/#include "meshtastic/#include "./g' *
|
|
||||||
@REM sed -i 's/meshtastic_//g' *
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ echo "prebuilt binaries for your computer into nanopb-0.4.7"
|
|||||||
|
|
||||||
# the nanopb tool seems to require that the .options file be in the current directory!
|
# the nanopb tool seems to require that the .options file be in the current directory!
|
||||||
cd protobufs
|
cd protobufs
|
||||||
../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated/ -I=../protobufs meshtastic/*.proto
|
../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated/ -I=../protobufs meshtastic/*.proto --experimental_allow_proto3_optional
|
||||||
|
|
||||||
# cd ../src/mesh/generated/meshtastic
|
# cd ../src/mesh/generated/meshtastic
|
||||||
# sed -i 's/#include "meshtastic/#include "./g' -- *
|
# sed -i 's/#include "meshtastic/#include "./g' -- *
|
||||||
|
|||||||
36
boards/bpi_picow_esp32_s3.json
Normal file
36
boards/bpi_picow_esp32_s3.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32s3_out.ld"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DARDUINO_USB_MODE=0",
|
||||||
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_EVENT_RUNNING_CORE=1",
|
||||||
|
"-DBOARD_HAS_PSRAM"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"hwids": [["0x303A", "0x1001"]],
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "bpi_picow_esp32_s3"
|
||||||
|
},
|
||||||
|
"connectivity": ["wifi"],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino", "espidf"],
|
||||||
|
"name": "BPI-PicoW-S3 (8 MB FLASH, 2 MB PSRAM)",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "8MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 8388608,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 921600
|
||||||
|
},
|
||||||
|
"url": "https://wiki.banana-pi.org/BPI-PicoW-S3",
|
||||||
|
"vendor": "BPI"
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"maximum_ram_size": 65536,
|
"maximum_ram_size": 65536,
|
||||||
"maximum_size": 262144,
|
"maximum_size": 262144,
|
||||||
"protocol": "cmsis-dap",
|
"protocol": "cmsis-dap",
|
||||||
"protocols": ["cmsis-dap"]
|
"protocols": ["cmsis-dap", "stlink"]
|
||||||
},
|
},
|
||||||
"url": "https://www.st.com/en/microcontrollers-microprocessors/stm32wl-series.html",
|
"url": "https://www.st.com/en/microcontrollers-microprocessors/stm32wl-series.html",
|
||||||
"vendor": "ST"
|
"vendor": "ST"
|
||||||
|
|||||||
38
boards/heltec_wireless_tracker.json
Normal file
38
boards/heltec_wireless_tracker.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32s3_out.ld",
|
||||||
|
"partitions": "default_8MB.csv"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DHELTEC_WIRELESS_TRACKER",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DARDUINO_USB_MODE=0",
|
||||||
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "qio",
|
||||||
|
"hwids": [["0x303A", "0x1001"]],
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "heltec_wireless_tracker"
|
||||||
|
},
|
||||||
|
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino", "espidf"],
|
||||||
|
"name": "Heltec Wireless Tracker",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "8MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 8388608,
|
||||||
|
"wait_for_upload_port": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 921600
|
||||||
|
},
|
||||||
|
"url": "https://heltec.org/project/wireless-tracker/",
|
||||||
|
"vendor": "Heltec"
|
||||||
|
}
|
||||||
41
boards/my-esp32s3-diy-oled.json
Normal file
41
boards/my-esp32s3-diy-oled.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32s3_out.ld",
|
||||||
|
"memory_type": "qio_opi"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DBOARD_HAS_PSRAM",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DARDUINO_USB_MODE=0",
|
||||||
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_EVENT_RUNNING_CORE=0"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "qio",
|
||||||
|
"hwids": [["0x303A", "0x1001"]],
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "my-esp32s3-diy-oled"
|
||||||
|
},
|
||||||
|
"connectivity": ["wifi"],
|
||||||
|
"debug": {
|
||||||
|
"default_tool": "esp-builtin",
|
||||||
|
"onboard_tools": ["esp-builtin"],
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino", "espidf"],
|
||||||
|
"name": "Clone ESP32-S3-DevKitC-1 v1.1 (16 MB FLASH, 8 MB PSRAM)",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "16MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 16777216,
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"wait_for_upload_port": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 921600
|
||||||
|
},
|
||||||
|
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html",
|
||||||
|
"vendor": "Espressif"
|
||||||
|
}
|
||||||
41
boards/my_esp32s3_diy_eink.json
Normal file
41
boards/my_esp32s3_diy_eink.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32s3_out.ld",
|
||||||
|
"memory_type": "qio_opi"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DBOARD_HAS_PSRAM",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DARDUINO_USB_MODE=0",
|
||||||
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_EVENT_RUNNING_CORE=0"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "qio",
|
||||||
|
"hwids": [["0x303A", "0x1001"]],
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "my_esp32s3_diy_eink"
|
||||||
|
},
|
||||||
|
"connectivity": ["wifi"],
|
||||||
|
"debug": {
|
||||||
|
"default_tool": "esp-builtin",
|
||||||
|
"onboard_tools": ["esp-builtin"],
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino", "espidf"],
|
||||||
|
"name": "Clone ESP32-S3-DevKitC-1 v1.1 (16 MB FLASH, 8 MB PSRAM)",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "16MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 16777216,
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"wait_for_upload_port": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 921600
|
||||||
|
},
|
||||||
|
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html",
|
||||||
|
"vendor": "Espressif"
|
||||||
|
}
|
||||||
51
boards/nano-g2-ultra.json
Normal file
51
boards/nano-g2-ultra.json
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "nrf52840_s140_v6.ld"
|
||||||
|
},
|
||||||
|
"core": "nRF5",
|
||||||
|
"cpu": "cortex-m4",
|
||||||
|
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
|
||||||
|
"f_cpu": "64000000L",
|
||||||
|
"hwids": [
|
||||||
|
["0x239A", "0x8029"],
|
||||||
|
["0x239A", "0x0029"],
|
||||||
|
["0x239A", "0x002A"],
|
||||||
|
["0x239A", "0x802A"]
|
||||||
|
],
|
||||||
|
"usb_product": "BQ nRF52840",
|
||||||
|
"mcu": "nrf52840",
|
||||||
|
"variant": "nano-g2-ultra",
|
||||||
|
"bsp": {
|
||||||
|
"name": "adafruit"
|
||||||
|
},
|
||||||
|
"softdevice": {
|
||||||
|
"sd_flags": "-DS140",
|
||||||
|
"sd_name": "s140",
|
||||||
|
"sd_version": "6.1.1",
|
||||||
|
"sd_fwid": "0x00B6"
|
||||||
|
},
|
||||||
|
"bootloader": {
|
||||||
|
"settings_addr": "0xFF000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectivity": ["bluetooth"],
|
||||||
|
"debug": {
|
||||||
|
"jlink_device": "nRF52840_xxAA",
|
||||||
|
"svd_path": "nrf52840.svd"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino"],
|
||||||
|
"name": "BQ nRF52840",
|
||||||
|
"upload": {
|
||||||
|
"maximum_ram_size": 248832,
|
||||||
|
"maximum_size": 815104,
|
||||||
|
"speed": 115200,
|
||||||
|
"protocol": "nrfutil",
|
||||||
|
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"wait_for_upload_port": true
|
||||||
|
},
|
||||||
|
"url": "https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra",
|
||||||
|
"vendor": "BQ Consulting"
|
||||||
|
}
|
||||||
40
boards/t-deck.json
Normal file
40
boards/t-deck.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32s3_out.ld"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DBOARD_HAS_PSRAM",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DARDUINO_USB_MODE=0",
|
||||||
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_EVENT_RUNNING_CORE=0"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"hwids": [["0x303A", "0x1001"]],
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "t-deck"
|
||||||
|
},
|
||||||
|
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||||
|
"debug": {
|
||||||
|
"default_tool": "esp-builtin",
|
||||||
|
"onboard_tools": ["esp-builtin"],
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino", "espidf"],
|
||||||
|
"name": "Espressif Systems LilyGO T-Deck (16 MB FLASH, 8 MB PSRAM)",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "16MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 16777216,
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"wait_for_upload_port": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 921600
|
||||||
|
},
|
||||||
|
"url": "https://www.lilygo.cc/en-pl/products/t-deck",
|
||||||
|
"vendor": "LilyGO"
|
||||||
|
}
|
||||||
@@ -7,7 +7,10 @@
|
|||||||
"cpu": "cortex-m4",
|
"cpu": "cortex-m4",
|
||||||
"extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA",
|
"extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA",
|
||||||
"f_cpu": "64000000L",
|
"f_cpu": "64000000L",
|
||||||
"hwids": [["0x239A", "0x4405"]],
|
"hwids": [
|
||||||
|
["0x239A", "0x4405"],
|
||||||
|
["0x239A", "0x002A"]
|
||||||
|
],
|
||||||
"usb_product": "TTGO_eink",
|
"usb_product": "TTGO_eink",
|
||||||
"mcu": "nrf52840",
|
"mcu": "nrf52840",
|
||||||
"variant": "t-echo",
|
"variant": "t-echo",
|
||||||
|
|||||||
38
boards/t-watch-s3.json
Normal file
38
boards/t-watch-s3.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32s3_out.ld"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DBOARD_HAS_PSRAM",
|
||||||
|
"-DT_WATCH_S3",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DARDUINO_USB_MODE=0",
|
||||||
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"hwids": [["0x303A", "0x1001"]],
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "t-watch-s3"
|
||||||
|
},
|
||||||
|
"connectivity": ["wifi"],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino"],
|
||||||
|
"name": "LilyGo T-Watch 2020 V3",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "8MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 8388608,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"wait_for_upload_port": true
|
||||||
|
},
|
||||||
|
"url": "http://www.lilygo.cn/",
|
||||||
|
"vendor": "LilyGo"
|
||||||
|
}
|
||||||
@@ -9,12 +9,13 @@
|
|||||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
"-DARDUINO_USB_MODE=0",
|
"-DARDUINO_USB_MODE=0",
|
||||||
"-DARDUINO_RUNNING_CORE=1",
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
"-DARDUINO_EVENT_RUNNING_CORE=1",
|
||||||
|
"-DBOARD_HAS_PSRAM"
|
||||||
],
|
],
|
||||||
"f_cpu": "240000000L",
|
"f_cpu": "240000000L",
|
||||||
"f_flash": "80000000L",
|
"f_flash": "80000000L",
|
||||||
"flash_mode": "dio",
|
"flash_mode": "dio",
|
||||||
"hwids": [["0X303A", "0x1001"]],
|
"hwids": [["0x303A", "0x1001"]],
|
||||||
"mcu": "esp32s3",
|
"mcu": "esp32s3",
|
||||||
"variant": "tlora-t3s3-v1"
|
"variant": "tlora-t3s3-v1"
|
||||||
},
|
},
|
||||||
|
|||||||
40
boards/wiscore_rak11300.json
Normal file
40
boards/wiscore_rak11300.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"earlephilhower": {
|
||||||
|
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||||
|
"usb_vid": "0x2E8A",
|
||||||
|
"usb_pid": "0x000A"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"core": "earlephilhower",
|
||||||
|
"cpu": "cortex-m0plus",
|
||||||
|
"extra_flags": "-DARDUINO_GENERIC_RP2040 -DRASPBERRY_PI_PICO -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
|
||||||
|
"f_cpu": "133000000L",
|
||||||
|
"hwids": [
|
||||||
|
["0x2E8A", "0x00C0"],
|
||||||
|
["0x2E8A", "0x000A"]
|
||||||
|
],
|
||||||
|
"mcu": "rp2040",
|
||||||
|
"variant": "WisBlock_RAK11300_Board"
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"jlink_device": "RP2040_M0_0",
|
||||||
|
"openocd_target": "rp2040.cfg",
|
||||||
|
"svd_path": "rp2040.svd"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino"],
|
||||||
|
"name": "WisBlock RAK11300",
|
||||||
|
"upload": {
|
||||||
|
"maximum_ram_size": 270336,
|
||||||
|
"maximum_size": 2097152,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"native_usb": true,
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"wait_for_upload_port": false,
|
||||||
|
"protocol": "picotool",
|
||||||
|
"protocols": ["cmsis-dap", "raspberrypi-swd", "picotool", "picoprobe"]
|
||||||
|
},
|
||||||
|
"url": "https://docs.rakwireless.com/",
|
||||||
|
"vendor": "RAKwireless"
|
||||||
|
}
|
||||||
57
boards/xiao_ble_sense.json
Normal file
57
boards/xiao_ble_sense.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "nrf52840_s140_v7.ld"
|
||||||
|
},
|
||||||
|
"core": "nRF5",
|
||||||
|
"cpu": "cortex-m4",
|
||||||
|
"extra_flags": "-DARDUINO_MDBT50Q_RX -DNRF52840_XXAA",
|
||||||
|
"f_cpu": "64000000L",
|
||||||
|
"hwids": [
|
||||||
|
["0x239A", "0x810B"],
|
||||||
|
["0x239A", "0x010B"],
|
||||||
|
["0x239A", "0x810C"]
|
||||||
|
],
|
||||||
|
"usb_product": "XIAO-BOOT",
|
||||||
|
"mcu": "nrf52840",
|
||||||
|
"variant": "Seeed_XIAO_nRF52840_Sense",
|
||||||
|
"bsp": {
|
||||||
|
"name": "adafruit"
|
||||||
|
},
|
||||||
|
"softdevice": {
|
||||||
|
"sd_flags": "-DS140",
|
||||||
|
"sd_name": "s140",
|
||||||
|
"sd_version": "7.3.0",
|
||||||
|
"sd_fwid": "0x0123"
|
||||||
|
},
|
||||||
|
"bootloader": {
|
||||||
|
"settings_addr": "0xFF000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectivity": ["bluetooth"],
|
||||||
|
"debug": {
|
||||||
|
"jlink_device": "nRF52840_xxAA",
|
||||||
|
"svd_path": "nrf52840.svd"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino"],
|
||||||
|
"name": "Seeed Xiao BLE Sense",
|
||||||
|
"upload": {
|
||||||
|
"maximum_ram_size": 248832,
|
||||||
|
"maximum_size": 815104,
|
||||||
|
"speed": 115200,
|
||||||
|
"protocol": "nrfutil",
|
||||||
|
"protocols": [
|
||||||
|
"jlink",
|
||||||
|
"nrfjprog",
|
||||||
|
"nrfutil",
|
||||||
|
"stlink",
|
||||||
|
"cmsis-dap",
|
||||||
|
"blackmagic"
|
||||||
|
],
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"wait_for_upload_port": true
|
||||||
|
},
|
||||||
|
"url": "https://www.seeedstudio.com/Seeed-XIAO-BLE-Sense-nRF52840-p-5253.html",
|
||||||
|
"vendor": "Seeed Studio"
|
||||||
|
}
|
||||||
155
monitor/filter_c3_exception_decoder.py
Normal file
155
monitor/filter_c3_exception_decoder.py
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from platformio.project.exception import PlatformioException
|
||||||
|
from platformio.public import (
|
||||||
|
DeviceMonitorFilterBase,
|
||||||
|
load_build_metadata,
|
||||||
|
)
|
||||||
|
|
||||||
|
# By design, __init__ is called inside miniterm and we can't pass context to it.
|
||||||
|
# pylint: disable=attribute-defined-outside-init
|
||||||
|
|
||||||
|
IS_WINDOWS = sys.platform.startswith("win")
|
||||||
|
|
||||||
|
|
||||||
|
class Esp32C3ExceptionDecoder(DeviceMonitorFilterBase):
|
||||||
|
NAME = "esp32_c3_exception_decoder"
|
||||||
|
|
||||||
|
PCADDR_PATTERN = re.compile(r'0x4[0-9a-f]{7}', re.IGNORECASE)
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
self.buffer = ""
|
||||||
|
self.pcaddr_re = self.PCADDR_PATTERN
|
||||||
|
|
||||||
|
self.firmware_path = None
|
||||||
|
self.addr2line_path = None
|
||||||
|
self.enabled = self.setup_paths()
|
||||||
|
|
||||||
|
if self.config.get("env:" + self.environment, "build_type") != "debug":
|
||||||
|
print(
|
||||||
|
"""
|
||||||
|
Please build project in debug configuration to get more details about an exception.
|
||||||
|
See https://docs.platformio.org/page/projectconf/build_configurations.html
|
||||||
|
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def setup_paths(self):
|
||||||
|
self.project_dir = os.path.abspath(self.project_dir)
|
||||||
|
try:
|
||||||
|
data = load_build_metadata(self.project_dir, self.environment)
|
||||||
|
self.firmware_path = data["prog_path"]
|
||||||
|
if not os.path.isfile(self.firmware_path):
|
||||||
|
sys.stderr.write(
|
||||||
|
"%s: disabling, firmware at %s does not exist, rebuild the project?\n"
|
||||||
|
% (self.__class__.__name__, self.firmware_path)
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.addr2line_path is None:
|
||||||
|
cc_path = data.get("cc_path", "")
|
||||||
|
if "-gcc" in cc_path:
|
||||||
|
self.addr2line_path = cc_path.replace("-gcc", "-addr2line")
|
||||||
|
else:
|
||||||
|
sys.stderr.write(
|
||||||
|
"%s: disabling, failed to find addr2line.\n"
|
||||||
|
% self.__class__.__name__
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not os.path.isfile(self.addr2line_path):
|
||||||
|
sys.stderr.write(
|
||||||
|
"%s: disabling, addr2line at %s does not exist\n"
|
||||||
|
% (self.__class__.__name__, self.addr2line_path)
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
except PlatformioException as e:
|
||||||
|
sys.stderr.write(
|
||||||
|
"%s: disabling, exception while looking for addr2line: %s\n"
|
||||||
|
% (self.__class__.__name__, e)
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def rx(self, text):
|
||||||
|
if not self.enabled:
|
||||||
|
return text
|
||||||
|
|
||||||
|
last = 0
|
||||||
|
while True:
|
||||||
|
idx = text.find("\n", last)
|
||||||
|
if idx == -1:
|
||||||
|
if len(self.buffer) < 4096:
|
||||||
|
self.buffer += text[last:]
|
||||||
|
break
|
||||||
|
|
||||||
|
line = text[last:idx]
|
||||||
|
if self.buffer:
|
||||||
|
line = self.buffer + line
|
||||||
|
self.buffer = ""
|
||||||
|
last = idx + 1
|
||||||
|
|
||||||
|
# Output each trace on a separate line below ours
|
||||||
|
# Logic identical to https://github.com/espressif/esp-idf/blob/master/tools/idf_monitor_base/logger.py#L131
|
||||||
|
for m in re.finditer(self.pcaddr_re, line):
|
||||||
|
if m is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
trace = self.get_backtrace(m)
|
||||||
|
if len(trace) != "":
|
||||||
|
text = text[: last] + trace + text[last :]
|
||||||
|
last += len(trace)
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
def get_backtrace(self, match):
|
||||||
|
trace = "\n"
|
||||||
|
enc = "mbcs" if IS_WINDOWS else "utf-8"
|
||||||
|
args = [self.addr2line_path, u"-fipC", u"-e", self.firmware_path]
|
||||||
|
try:
|
||||||
|
addr = match.group()
|
||||||
|
output = (
|
||||||
|
subprocess.check_output(args + [addr])
|
||||||
|
.decode(enc)
|
||||||
|
.strip()
|
||||||
|
)
|
||||||
|
output = output.replace(
|
||||||
|
"\n", "\n "
|
||||||
|
) # newlines happen with inlined methods
|
||||||
|
output = self.strip_project_dir(output)
|
||||||
|
# Output the trace in yellow color so that it is easier to spot
|
||||||
|
trace += "\033[33m=> %s: %s\033[0m\n" % (addr, output)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
sys.stderr.write(
|
||||||
|
"%s: failed to call %s: %s\n"
|
||||||
|
% (self.__class__.__name__, self.addr2line_path, e)
|
||||||
|
)
|
||||||
|
return trace
|
||||||
|
|
||||||
|
def strip_project_dir(self, trace):
|
||||||
|
while True:
|
||||||
|
idx = trace.find(self.project_dir)
|
||||||
|
if idx == -1:
|
||||||
|
break
|
||||||
|
trace = trace[:idx] + trace[idx + len(self.project_dir) + 1 :]
|
||||||
|
return trace
|
||||||
@@ -7,12 +7,14 @@
|
|||||||
;default_envs = tbeam-s3-core
|
;default_envs = tbeam-s3-core
|
||||||
;default_envs = tbeam0.7
|
;default_envs = tbeam0.7
|
||||||
;default_envs = heltec-v1
|
;default_envs = heltec-v1
|
||||||
;default_envs = heltec-v2.0
|
;default_envs = heltec-v2_0
|
||||||
;default_envs = heltec-v2.1
|
;default_envs = heltec-v2_1
|
||||||
|
;default_envs = heltec-wireless-tracker
|
||||||
;default_envs = tlora-v1
|
;default_envs = tlora-v1
|
||||||
;default_envs = tlora_v1_3
|
;default_envs = tlora_v1_3
|
||||||
;default_envs = tlora-v2
|
;default_envs = tlora-v2
|
||||||
;default_envs = tlora-v2-1-1.6
|
;default_envs = tlora-v2-1-1_6
|
||||||
|
;default_envs = tlora-t3s3-v1
|
||||||
;default_envs = lora-relay-v1 # nrf board
|
;default_envs = lora-relay-v1 # nrf board
|
||||||
;default_envs = t-echo
|
;default_envs = t-echo
|
||||||
;default_envs = nrf52840dk-geeksville
|
;default_envs = nrf52840dk-geeksville
|
||||||
@@ -20,17 +22,18 @@
|
|||||||
;default_envs = nano-g1
|
;default_envs = nano-g1
|
||||||
;default_envs = pca10059_diy_eink
|
;default_envs = pca10059_diy_eink
|
||||||
;default_envs = meshtastic-diy-v1
|
;default_envs = meshtastic-diy-v1
|
||||||
;default_envs = meshtastic-diy-v1.1
|
;default_envs = meshtastic-diy-v1_1
|
||||||
;default_envs = meshtastic-dr-dev
|
;default_envs = meshtastic-dr-dev
|
||||||
;default_envs = m5stack-coreink
|
;default_envs = m5stack-coreink
|
||||||
;default_envs = rak4631
|
;default_envs = rak4631
|
||||||
|
default_envs = wio-e5
|
||||||
|
|
||||||
extra_configs =
|
extra_configs =
|
||||||
arch/*/*.ini
|
arch/*/*.ini
|
||||||
variants/*/platformio.ini
|
variants/*/platformio.ini
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
extra_scripts = bin/platformio-custom.py
|
extra_scripts = bin/platformio-custom.py
|
||||||
|
|
||||||
; note: we add src to our include search path so that lmic_project_config can override
|
; note: we add src to our include search path so that lmic_project_config can override
|
||||||
; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile
|
; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile
|
||||||
@@ -38,8 +41,8 @@ extra_scripts = bin/platformio-custom.py
|
|||||||
; 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.
|
; 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/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
|
-Isrc -Isrc/mesh -Isrc/mesh/generated -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
|
||||||
@@ -54,19 +57,23 @@ build_flags = -Wno-missing-field-initializers
|
|||||||
-DRADIOLIB_EXCLUDE_MORSE
|
-DRADIOLIB_EXCLUDE_MORSE
|
||||||
-DRADIOLIB_EXCLUDE_RTTY
|
-DRADIOLIB_EXCLUDE_RTTY
|
||||||
-DRADIOLIB_EXCLUDE_SSTV
|
-DRADIOLIB_EXCLUDE_SSTV
|
||||||
|
-DRADIOLIB_EXCLUDE_AX25
|
||||||
|
-DRADIOLIB_EXCLUDE_DIRECT_RECEIVE
|
||||||
|
-DRADIOLIB_EXCLUDE_BELL
|
||||||
|
-DRADIOLIB_EXCLUDE_PAGER
|
||||||
|
-DRADIOLIB_EXCLUDE_FSK4
|
||||||
|
-DRADIOLIB_EXCLUDE_APRS
|
||||||
|
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#da1ede4dfcd91074283b029080759fd744120909 ; ESP8266_SSD1306
|
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306
|
||||||
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
|
https://github.com/mathertel/OneButton#2.1.0 ; OneButton library for non-blocking button debounce
|
||||||
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
|
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
|
||||||
https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
|
https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
|
||||||
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||||
nanopb/Nanopb@^0.4.6
|
nanopb/Nanopb@^0.4.7
|
||||||
erriez/ErriezCRC32@^1.0.1
|
erriez/ErriezCRC32@^1.0.1
|
||||||
; jgromes/RadioLib@^5.5.1
|
|
||||||
https://github.com/jgromes/RadioLib.git#7a25b27c3183ffe3627c5c221243c378d8951da7
|
|
||||||
|
|
||||||
; Used for the code analysis in PIO Home / Inspect
|
; Used for the code analysis in PIO Home / Inspect
|
||||||
check_tool = cppcheck
|
check_tool = cppcheck
|
||||||
@@ -81,31 +88,37 @@ check_flags =
|
|||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
mprograms/QMC5883LCompass@^1.1.1
|
mprograms/QMC5883LCompass@^1.2.0
|
||||||
end2endzone/NonBlockingRTTTL@^1.3.0
|
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
|
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
|
||||||
|
|
||||||
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
|
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
|
||||||
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
|
||||||
[networking_base]
|
[networking_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
knolleary/PubSubClient@^2.8
|
knolleary/PubSubClient@^2.8
|
||||||
arduino-libraries/NTPClient@^3.1.0
|
arduino-libraries/NTPClient@^3.1.0
|
||||||
|
arcao/Syslog@^2.0.0
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
; (not included in native / portduino)
|
; (not included in native / portduino)
|
||||||
[environmental_base]
|
[environmental_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
adafruit/Adafruit BusIO@^1.11.4
|
adafruit/Adafruit BusIO@^1.11.4
|
||||||
adafruit/Adafruit Unified Sensor@^1.1.4
|
adafruit/Adafruit Unified Sensor@^1.1.11
|
||||||
adafruit/Adafruit BMP280 Library@^2.6.6
|
adafruit/Adafruit BMP280 Library@^2.6.8
|
||||||
adafruit/Adafruit BME280 Library@^2.2.2
|
adafruit/Adafruit BME280 Library@^2.2.2
|
||||||
adafruit/Adafruit BME680 Library@^2.0.1
|
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
|
||||||
|
boschsensortec/BME68x Sensor Library@^1.1.40407
|
||||||
adafruit/Adafruit MCP9808 Library@^2.0.0
|
adafruit/Adafruit MCP9808 Library@^2.0.0
|
||||||
adafruit/Adafruit INA260 Library@^1.5.0
|
adafruit/Adafruit INA260 Library@^1.5.0
|
||||||
adafruit/Adafruit INA219@^1.2.0
|
adafruit/Adafruit INA219@^1.2.0
|
||||||
adafruit/Adafruit SHTC3 Library@^1.0.0
|
adafruit/Adafruit SHTC3 Library@^1.0.0
|
||||||
adafruit/Adafruit LPS2X@^2.0.4
|
adafruit/Adafruit LPS2X@^2.0.4
|
||||||
adafruit/Adafruit SHT31 Library@^2.2.0
|
adafruit/Adafruit SHT31 Library@^2.2.2
|
||||||
|
adafruit/Adafruit PM25 AQI Sensor@^1.0.6
|
||||||
|
adafruit/Adafruit MPU6050@^2.2.4
|
||||||
|
adafruit/Adafruit LIS3DH@^1.2.4
|
||||||
|
https://github.com/lewisxhe/BMA423_Library@^0.0.1
|
||||||
Submodule protobufs updated: 0754d58205...468ff2e245
174
src/AccelerometerThread.h
Normal file
174
src/AccelerometerThread.h
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
#include "PowerFSM.h"
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "power.h"
|
||||||
|
|
||||||
|
#include <Adafruit_LIS3DH.h>
|
||||||
|
#include <Adafruit_MPU6050.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <bma.h>
|
||||||
|
|
||||||
|
BMA423 bmaSensor;
|
||||||
|
bool BMA_IRQ = false;
|
||||||
|
|
||||||
|
#define ACCELEROMETER_CHECK_INTERVAL_MS 100
|
||||||
|
#define ACCELEROMETER_CLICK_THRESHOLD 40
|
||||||
|
|
||||||
|
uint16_t readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
|
||||||
|
{
|
||||||
|
Wire.beginTransmission(address);
|
||||||
|
Wire.write(reg);
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.requestFrom((uint8_t)address, (uint8_t)len);
|
||||||
|
uint8_t i = 0;
|
||||||
|
while (Wire.available()) {
|
||||||
|
data[i++] = Wire.read();
|
||||||
|
}
|
||||||
|
return 0; // Pass
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
|
||||||
|
{
|
||||||
|
Wire.beginTransmission(address);
|
||||||
|
Wire.write(reg);
|
||||||
|
Wire.write(data, len);
|
||||||
|
return (0 != Wire.endTransmission());
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace concurrency
|
||||||
|
{
|
||||||
|
class AccelerometerThread : public concurrency::OSThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccelerometerThread(ScanI2C::DeviceType type = ScanI2C::DeviceType::NONE) : OSThread("AccelerometerThread")
|
||||||
|
{
|
||||||
|
if (accelerometer_found.port == ScanI2C::I2CPort::NO_I2C) {
|
||||||
|
LOG_DEBUG("AccelerometerThread disabling due to no sensors found\n");
|
||||||
|
disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.display.wake_on_tap_or_motion && !config.device.double_tap_as_button_press) {
|
||||||
|
LOG_DEBUG("AccelerometerThread disabling due to no interested configurations\n");
|
||||||
|
disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acceleremoter_type = type;
|
||||||
|
LOG_DEBUG("AccelerometerThread initializing\n");
|
||||||
|
|
||||||
|
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.begin(accelerometer_found.address)) {
|
||||||
|
LOG_DEBUG("MPU6050 initializing\n");
|
||||||
|
// setup motion detection
|
||||||
|
mpu.setHighPassFilter(MPU6050_HIGHPASS_0_63_HZ);
|
||||||
|
mpu.setMotionDetectionThreshold(1);
|
||||||
|
mpu.setMotionDetectionDuration(20);
|
||||||
|
mpu.setInterruptPinLatch(true); // Keep it latched. Will turn off when reinitialized.
|
||||||
|
mpu.setInterruptPinPolarity(true);
|
||||||
|
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.begin(accelerometer_found.address)) {
|
||||||
|
LOG_DEBUG("LIS3DH initializing\n");
|
||||||
|
lis.setRange(LIS3DH_RANGE_2_G);
|
||||||
|
// Adjust threshold, higher numbers are less sensitive
|
||||||
|
lis.setClick(config.device.double_tap_as_button_press ? 2 : 1, ACCELEROMETER_CLICK_THRESHOLD);
|
||||||
|
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.begin(readRegister, writeRegister, delay)) {
|
||||||
|
LOG_DEBUG("BMA423 initializing\n");
|
||||||
|
Acfg cfg;
|
||||||
|
cfg.odr = BMA4_OUTPUT_DATA_RATE_100HZ;
|
||||||
|
cfg.range = BMA4_ACCEL_RANGE_2G;
|
||||||
|
cfg.bandwidth = BMA4_ACCEL_NORMAL_AVG4;
|
||||||
|
cfg.perf_mode = BMA4_CONTINUOUS_MODE;
|
||||||
|
bmaSensor.setAccelConfig(cfg);
|
||||||
|
bmaSensor.enableAccel();
|
||||||
|
|
||||||
|
struct bma4_int_pin_config pin_config;
|
||||||
|
pin_config.edge_ctrl = BMA4_LEVEL_TRIGGER;
|
||||||
|
pin_config.lvl = BMA4_ACTIVE_HIGH;
|
||||||
|
pin_config.od = BMA4_PUSH_PULL;
|
||||||
|
pin_config.output_en = BMA4_OUTPUT_ENABLE;
|
||||||
|
pin_config.input_en = BMA4_INPUT_DISABLE;
|
||||||
|
// The correct trigger interrupt needs to be configured as needed
|
||||||
|
bmaSensor.setINTPinConfig(pin_config, BMA4_INTR1_MAP);
|
||||||
|
|
||||||
|
#ifdef BMA423_INT
|
||||||
|
pinMode(BMA4XX_INT, INPUT);
|
||||||
|
attachInterrupt(
|
||||||
|
BMA4XX_INT,
|
||||||
|
[] {
|
||||||
|
// Set interrupt to set irq value to true
|
||||||
|
BMA_IRQ = true;
|
||||||
|
},
|
||||||
|
RISING); // Select the interrupt mode according to the actual circuit
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct bma423_axes_remap remap_data;
|
||||||
|
remap_data.x_axis = 0;
|
||||||
|
remap_data.x_axis_sign = 1;
|
||||||
|
remap_data.y_axis = 1;
|
||||||
|
remap_data.y_axis_sign = 0;
|
||||||
|
remap_data.z_axis = 2;
|
||||||
|
remap_data.z_axis_sign = 1;
|
||||||
|
// Need to raise the wrist function, need to set the correct axis
|
||||||
|
bmaSensor.setRemapAxes(&remap_data);
|
||||||
|
// sensor.enableFeature(BMA423_STEP_CNTR, true);
|
||||||
|
bmaSensor.enableFeature(BMA423_TILT, true);
|
||||||
|
bmaSensor.enableFeature(BMA423_WAKEUP, true);
|
||||||
|
// sensor.resetStepCounter();
|
||||||
|
|
||||||
|
// Turn on feature interrupt
|
||||||
|
bmaSensor.enableStepCountInterrupt();
|
||||||
|
bmaSensor.enableTiltInterrupt();
|
||||||
|
// It corresponds to isDoubleClick interrupt
|
||||||
|
bmaSensor.enableWakeupInterrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int32_t runOnce() override
|
||||||
|
{
|
||||||
|
canSleep = true; // Assume we should not keep the board awake
|
||||||
|
|
||||||
|
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) {
|
||||||
|
wakeScreen();
|
||||||
|
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) {
|
||||||
|
uint8_t click = lis.getClick();
|
||||||
|
if (!config.device.double_tap_as_button_press) {
|
||||||
|
wakeScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.device.double_tap_as_button_press && (click & 0x20)) {
|
||||||
|
buttonPress();
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.getINT()) {
|
||||||
|
if (bmaSensor.isTilt() || bmaSensor.isDoubleClick()) {
|
||||||
|
wakeScreen();
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ACCELEROMETER_CHECK_INTERVAL_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void wakeScreen()
|
||||||
|
{
|
||||||
|
if (powerFSM.getState() == &stateDARK) {
|
||||||
|
LOG_INFO("Tap or motion detected. Turning on screen\n");
|
||||||
|
powerFSM.trigger(EVENT_INPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void buttonPress()
|
||||||
|
{
|
||||||
|
LOG_DEBUG("Double-tap detected. Firing button press\n");
|
||||||
|
powerFSM.trigger(EVENT_PRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::DeviceType acceleremoter_type;
|
||||||
|
Adafruit_MPU6050 mpu;
|
||||||
|
Adafruit_LIS3DH lis;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace concurrency
|
||||||
@@ -17,4 +17,14 @@
|
|||||||
extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[];
|
extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[];
|
||||||
|
|
||||||
/// Given a level between 0-100, update the BLE attribute
|
/// Given a level between 0-100, update the BLE attribute
|
||||||
void updateBatteryLevel(uint8_t level);
|
void updateBatteryLevel(uint8_t level);
|
||||||
|
|
||||||
|
class BluetoothApi
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void setup();
|
||||||
|
virtual void shutdown();
|
||||||
|
virtual void clearBonds();
|
||||||
|
virtual bool isConnected();
|
||||||
|
virtual int getRssi() = 0;
|
||||||
|
};
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "concurrency/OSThread.h"
|
#include "concurrency/OSThread.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "graphics/Screen.h"
|
#include "graphics/Screen.h"
|
||||||
|
#include "main.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include <OneButton.h>
|
#include <OneButton.h>
|
||||||
|
|
||||||
@@ -45,19 +46,19 @@ class ButtonThread : public concurrency::OSThread
|
|||||||
ButtonThread() : OSThread("Button")
|
ButtonThread() : OSThread("Button")
|
||||||
{
|
{
|
||||||
#ifdef BUTTON_PIN
|
#ifdef BUTTON_PIN
|
||||||
userButton = OneButton(BUTTON_PIN, true, true);
|
userButton = OneButton(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, true, true);
|
||||||
#ifdef INPUT_PULLUP_SENSE
|
#ifdef INPUT_PULLUP_SENSE
|
||||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||||
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
|
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP_SENSE);
|
||||||
#endif
|
#endif
|
||||||
userButton.attachClick(userButtonPressed);
|
userButton.attachClick(userButtonPressed);
|
||||||
userButton.setClickTicks(300);
|
userButton.setClickMs(300);
|
||||||
userButton.attachDuringLongPress(userButtonPressedLong);
|
userButton.attachDuringLongPress(userButtonPressedLong);
|
||||||
userButton.attachDoubleClick(userButtonDoublePressed);
|
userButton.attachDoubleClick(userButtonDoublePressed);
|
||||||
userButton.attachMultiClick(userButtonMultiPressed);
|
userButton.attachMultiClick(userButtonMultiPressed);
|
||||||
userButton.attachLongPressStart(userButtonPressedLongStart);
|
userButton.attachLongPressStart(userButtonPressedLongStart);
|
||||||
userButton.attachLongPressStop(userButtonPressedLongStop);
|
userButton.attachLongPressStop(userButtonPressedLongStop);
|
||||||
wakeOnIrq(BUTTON_PIN, FALLING);
|
wakeOnIrq(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, FALLING);
|
||||||
#endif
|
#endif
|
||||||
#ifdef BUTTON_PIN_ALT
|
#ifdef BUTTON_PIN_ALT
|
||||||
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
|
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
|
||||||
@@ -98,10 +99,10 @@ class ButtonThread : public concurrency::OSThread
|
|||||||
userButtonTouch.tick();
|
userButtonTouch.tick();
|
||||||
canSleep &= userButtonTouch.isIdle();
|
canSleep &= userButtonTouch.isIdle();
|
||||||
#endif
|
#endif
|
||||||
// if (!canSleep) LOG_DEBUG("Supressing sleep!\n");
|
// if (!canSleep) LOG_DEBUG("Suppressing sleep!\n");
|
||||||
// else LOG_DEBUG("sleep ok\n");
|
// else LOG_DEBUG("sleep ok\n");
|
||||||
|
|
||||||
return 5;
|
return 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -115,7 +116,9 @@ class ButtonThread : public concurrency::OSThread
|
|||||||
{
|
{
|
||||||
// LOG_DEBUG("press!\n");
|
// LOG_DEBUG("press!\n");
|
||||||
#ifdef BUTTON_PIN
|
#ifdef BUTTON_PIN
|
||||||
if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) || !moduleConfig.canned_message.enabled) {
|
if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
|
||||||
|
moduleConfig.canned_message.inputbroker_pin_press) ||
|
||||||
|
!moduleConfig.canned_message.enabled) {
|
||||||
powerFSM.trigger(EVENT_PRESS);
|
powerFSM.trigger(EVENT_PRESS);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -123,17 +126,9 @@ class ButtonThread : public concurrency::OSThread
|
|||||||
static void userButtonPressedLong()
|
static void userButtonPressedLong()
|
||||||
{
|
{
|
||||||
// LOG_DEBUG("Long press!\n");
|
// LOG_DEBUG("Long press!\n");
|
||||||
#ifdef ARCH_ESP32
|
|
||||||
screen->adjustBrightness();
|
|
||||||
#endif
|
|
||||||
// If user button is held down for 5 seconds, shutdown the device.
|
// If user button is held down for 5 seconds, shutdown the device.
|
||||||
if ((millis() - longPressTime > 5 * 1000) && (longPressTime > 0)) {
|
if ((millis() - longPressTime > 5000) && (longPressTime > 0)) {
|
||||||
#ifdef HAS_PMU
|
#if defined(ARCH_NRF52) || defined(ARCH_ESP32)
|
||||||
if (pmu_found == true) {
|
|
||||||
setLed(false);
|
|
||||||
power->shutdown();
|
|
||||||
}
|
|
||||||
#elif defined(ARCH_NRF52)
|
|
||||||
// Do actual shutdown when button released, otherwise the button release
|
// Do actual shutdown when button released, otherwise the button release
|
||||||
// may wake the board immediatedly.
|
// may wake the board immediatedly.
|
||||||
if ((!shutdown_on_long_stop) && (millis() > 30 * 1000)) {
|
if ((!shutdown_on_long_stop) && (millis() > 30 * 1000)) {
|
||||||
@@ -163,7 +158,7 @@ class ButtonThread : public concurrency::OSThread
|
|||||||
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
|
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
|
||||||
#endif
|
#endif
|
||||||
screen->print("Sent ad-hoc ping\n");
|
screen->print("Sent ad-hoc ping\n");
|
||||||
service.refreshMyNodeInfo();
|
service.refreshLocalMeshNode();
|
||||||
service.sendNetworkPing(NODENUM_BROADCAST, true);
|
service.sendNetworkPing(NODENUM_BROADCAST, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,4 +197,4 @@ class ButtonThread : public concurrency::OSThread
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace concurrency
|
} // namespace concurrency
|
||||||
172
src/DebugConfiguration.cpp
Normal file
172
src/DebugConfiguration.cpp
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/* based on https://github.com/arcao/Syslog
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016 Martin Sloup
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.*/
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include "DebugConfiguration.h"
|
||||||
|
|
||||||
|
#if HAS_WIFI || HAS_ETHERNET
|
||||||
|
|
||||||
|
Syslog::Syslog(UDP &client)
|
||||||
|
{
|
||||||
|
this->_client = &client;
|
||||||
|
this->_server = NULL;
|
||||||
|
this->_port = 0;
|
||||||
|
this->_deviceHostname = SYSLOG_NILVALUE;
|
||||||
|
this->_appName = SYSLOG_NILVALUE;
|
||||||
|
this->_priDefault = LOGLEVEL_KERN;
|
||||||
|
}
|
||||||
|
|
||||||
|
Syslog &Syslog::server(const char *server, uint16_t port)
|
||||||
|
{
|
||||||
|
if (this->_ip.fromString(server)) {
|
||||||
|
this->_server = NULL;
|
||||||
|
} else {
|
||||||
|
this->_server = server;
|
||||||
|
}
|
||||||
|
this->_port = port;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Syslog &Syslog::server(IPAddress ip, uint16_t port)
|
||||||
|
{
|
||||||
|
this->_ip = ip;
|
||||||
|
this->_server = NULL;
|
||||||
|
this->_port = port;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Syslog &Syslog::deviceHostname(const char *deviceHostname)
|
||||||
|
{
|
||||||
|
this->_deviceHostname = (deviceHostname == NULL) ? SYSLOG_NILVALUE : deviceHostname;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Syslog &Syslog::appName(const char *appName)
|
||||||
|
{
|
||||||
|
this->_appName = (appName == NULL) ? SYSLOG_NILVALUE : appName;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Syslog &Syslog::defaultPriority(uint16_t pri)
|
||||||
|
{
|
||||||
|
this->_priDefault = pri;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Syslog &Syslog::logMask(uint8_t priMask)
|
||||||
|
{
|
||||||
|
this->_priMask = priMask;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Syslog::enable()
|
||||||
|
{
|
||||||
|
this->_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Syslog::disable()
|
||||||
|
{
|
||||||
|
this->_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Syslog::isEnabled()
|
||||||
|
{
|
||||||
|
return this->_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Syslog::vlogf(uint16_t pri, const char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
return this->vlogf(pri, this->_appName, fmt, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Syslog::vlogf(uint16_t pri, const char *appName, const char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
char *message;
|
||||||
|
size_t initialLen;
|
||||||
|
size_t len;
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
initialLen = strlen(fmt);
|
||||||
|
|
||||||
|
message = new char[initialLen + 1];
|
||||||
|
|
||||||
|
len = vsnprintf(message, initialLen + 1, fmt, args);
|
||||||
|
if (len > initialLen) {
|
||||||
|
delete[] message;
|
||||||
|
message = new char[len + 1];
|
||||||
|
|
||||||
|
vsnprintf(message, len + 1, fmt, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = this->_sendLog(pri, appName, message);
|
||||||
|
|
||||||
|
delete[] message;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Syslog::_sendLog(uint16_t pri, const char *appName, const char *message)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (!this->_enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((this->_server == NULL && this->_ip == INADDR_NONE) || this->_port == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check priority against priMask values.
|
||||||
|
if ((LOG_MASK(LOG_PRI(pri)) & this->_priMask) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Set default facility if none specified.
|
||||||
|
if ((pri & LOG_FACMASK) == 0)
|
||||||
|
pri = LOG_MAKEPRI(LOG_FAC(this->_priDefault), pri);
|
||||||
|
|
||||||
|
if (this->_server != NULL) {
|
||||||
|
result = this->_client->beginPacket(this->_server, this->_port);
|
||||||
|
} else {
|
||||||
|
result = this->_client->beginPacket(this->_ip, this->_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->_client->print('<');
|
||||||
|
this->_client->print(pri);
|
||||||
|
this->_client->print(F(">1 - "));
|
||||||
|
this->_client->print(this->_deviceHostname);
|
||||||
|
this->_client->print(' ');
|
||||||
|
this->_client->print(appName);
|
||||||
|
this->_client->print(F(" - - - \xEF\xBB\xBF"));
|
||||||
|
this->_client->print(F("["));
|
||||||
|
this->_client->print(int(millis() / 1000));
|
||||||
|
this->_client->print(F("]: "));
|
||||||
|
this->_client->print(message);
|
||||||
|
this->_client->endPacket();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
#ifndef SYSLOG_H
|
||||||
|
#define SYSLOG_H
|
||||||
|
|
||||||
// DEBUG LED
|
// DEBUG LED
|
||||||
#ifndef LED_INVERTED
|
#ifndef LED_INVERTED
|
||||||
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
|
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
|
||||||
@@ -17,6 +20,7 @@
|
|||||||
#define MESHTASTIC_LOG_LEVEL_INFO "INFO "
|
#define MESHTASTIC_LOG_LEVEL_INFO "INFO "
|
||||||
#define MESHTASTIC_LOG_LEVEL_WARN "WARN "
|
#define MESHTASTIC_LOG_LEVEL_WARN "WARN "
|
||||||
#define MESHTASTIC_LOG_LEVEL_ERROR "ERROR"
|
#define MESHTASTIC_LOG_LEVEL_ERROR "ERROR"
|
||||||
|
#define MESHTASTIC_LOG_LEVEL_CRIT "CRIT "
|
||||||
#define MESHTASTIC_LOG_LEVEL_TRACE "TRACE"
|
#define MESHTASTIC_LOG_LEVEL_TRACE "TRACE"
|
||||||
|
|
||||||
#include "SerialConsole.h"
|
#include "SerialConsole.h"
|
||||||
@@ -24,25 +28,77 @@
|
|||||||
#define DEBUG_PORT (*console) // Serial debug port
|
#define DEBUG_PORT (*console) // Serial debug port
|
||||||
|
|
||||||
#ifdef USE_SEGGER
|
#ifdef USE_SEGGER
|
||||||
|
#define DEBUG_PORT
|
||||||
#define LOG_DEBUG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
#define LOG_DEBUG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||||
#define LOG_INFO(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
#define LOG_INFO(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||||
#define LOG_WARN(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
#define LOG_WARN(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||||
#define LOG_ERROR(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
#define LOG_ERROR(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||||
|
#define LOG_CRIT(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||||
|
#define LOG_TRACE(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#ifdef DEBUG_PORT
|
#ifdef DEBUG_PORT
|
||||||
#define LOG_DEBUG(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
#define LOG_DEBUG(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
||||||
#define LOG_INFO(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__)
|
#define LOG_INFO(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__)
|
||||||
#define LOG_WARN(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__)
|
#define LOG_WARN(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__)
|
||||||
#define LOG_ERROR(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_ERROR, __VA_ARGS__)
|
#define LOG_ERROR(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_ERROR, __VA_ARGS__)
|
||||||
#define LOG_TRACE(...) DEBUG_PORT.log(MESHTASTIC_LOG_TRACE, __VA_ARGS__)
|
#define LOG_CRIT(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_CRIT, __VA_ARGS__)
|
||||||
|
#define LOG_TRACE(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_TRACE, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_DEBUG(...)
|
#define LOG_DEBUG(...)
|
||||||
#define LOG_INFO(...)
|
#define LOG_INFO(...)
|
||||||
#define LOG_WARN(...)
|
#define LOG_WARN(...)
|
||||||
#define LOG_ERROR(...)
|
#define LOG_ERROR(...)
|
||||||
|
#define LOG_CRIT(...)
|
||||||
|
#define LOG_TRACE(...)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SYSLOG_NILVALUE "-"
|
||||||
|
|
||||||
|
#define SYSLOG_CRIT 2 /* critical conditions */
|
||||||
|
#define SYSLOG_ERR 3 /* error conditions */
|
||||||
|
#define SYSLOG_WARN 4 /* warning conditions */
|
||||||
|
#define SYSLOG_INFO 6 /* informational */
|
||||||
|
#define SYSLOG_DEBUG 7 /* debug-level messages */
|
||||||
|
// trace does not go out to syslog (yet?)
|
||||||
|
|
||||||
|
#define LOG_PRIMASK 0x07 /* mask to extract priority part (internal) */
|
||||||
|
/* extract priority */
|
||||||
|
#define LOG_PRI(p) ((p)&LOG_PRIMASK)
|
||||||
|
#define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri))
|
||||||
|
|
||||||
|
/* facility codes */
|
||||||
|
#define LOGLEVEL_KERN (0 << 3) /* kernel messages */
|
||||||
|
#define LOGLEVEL_USER (1 << 3) /* random user-level messages */
|
||||||
|
#define LOGLEVEL_MAIL (2 << 3) /* mail system */
|
||||||
|
#define LOGLEVEL_DAEMON (3 << 3) /* system daemons */
|
||||||
|
#define LOGLEVEL_AUTH (4 << 3) /* security/authorization messages */
|
||||||
|
#define LOGLEVEL_SYSLOG (5 << 3) /* messages generated internally by syslogd */
|
||||||
|
#define LOGLEVEL_LPR (6 << 3) /* line printer subsystem */
|
||||||
|
#define LOGLEVEL_NEWS (7 << 3) /* network news subsystem */
|
||||||
|
#define LOGLEVEL_UUCP (8 << 3) /* UUCP subsystem */
|
||||||
|
#define LOGLEVEL_CRON (9 << 3) /* clock daemon */
|
||||||
|
#define LOGLEVEL_AUTHPRIV (10 << 3) /* security/authorization messages (private) */
|
||||||
|
#define LOGLEVEL_FTP (11 << 3) /* ftp daemon */
|
||||||
|
|
||||||
|
/* other codes through 15 reserved for system use */
|
||||||
|
#define LOGLEVEL_LOCAL0 (16 << 3) /* reserved for local use */
|
||||||
|
#define LOGLEVEL_LOCAL1 (17 << 3) /* reserved for local use */
|
||||||
|
#define LOGLEVEL_LOCAL2 (18 << 3) /* reserved for local use */
|
||||||
|
#define LOGLEVEL_LOCAL3 (19 << 3) /* reserved for local use */
|
||||||
|
#define LOGLEVEL_LOCAL4 (20 << 3) /* reserved for local use */
|
||||||
|
#define LOGLEVEL_LOCAL5 (21 << 3) /* reserved for local use */
|
||||||
|
#define LOGLEVEL_LOCAL6 (22 << 3) /* reserved for local use */
|
||||||
|
#define LOGLEVEL_LOCAL7 (23 << 3) /* reserved for local use */
|
||||||
|
|
||||||
|
#define LOG_NFACILITIES 24 /* current number of facilities */
|
||||||
|
#define LOG_FACMASK 0x03f8 /* mask to extract facility part */
|
||||||
|
/* facility of pri */
|
||||||
|
#define LOG_FAC(p) (((p)&LOG_FACMASK) >> 3)
|
||||||
|
|
||||||
|
#define LOG_MASK(pri) (1 << (pri)) /* mask for one priority */
|
||||||
|
#define LOG_UPTO(pri) ((1 << ((pri) + 1)) - 1) /* all priorities through pri */
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// AXP192 (Rev1-specific options)
|
// AXP192 (Rev1-specific options)
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -52,3 +108,50 @@
|
|||||||
|
|
||||||
// Default Bluetooth PIN
|
// Default Bluetooth PIN
|
||||||
#define defaultBLEPin 123456
|
#define defaultBLEPin 123456
|
||||||
|
|
||||||
|
#if HAS_ETHERNET
|
||||||
|
#include <RAK13800_W5100S.h>
|
||||||
|
#endif // HAS_ETHERNET
|
||||||
|
|
||||||
|
#if HAS_WIFI
|
||||||
|
#include <WiFi.h>
|
||||||
|
#endif // HAS_WIFI
|
||||||
|
|
||||||
|
#if HAS_WIFI || HAS_ETHERNET
|
||||||
|
|
||||||
|
class Syslog
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
UDP *_client;
|
||||||
|
IPAddress _ip;
|
||||||
|
const char *_server;
|
||||||
|
uint16_t _port;
|
||||||
|
const char *_deviceHostname;
|
||||||
|
const char *_appName;
|
||||||
|
uint16_t _priDefault;
|
||||||
|
uint8_t _priMask = 0xff;
|
||||||
|
bool _enabled = false;
|
||||||
|
|
||||||
|
bool _sendLog(uint16_t pri, const char *appName, const char *message);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Syslog(UDP &client);
|
||||||
|
|
||||||
|
Syslog &server(const char *server, uint16_t port);
|
||||||
|
Syslog &server(IPAddress ip, uint16_t port);
|
||||||
|
Syslog &deviceHostname(const char *deviceHostname);
|
||||||
|
Syslog &appName(const char *appName);
|
||||||
|
Syslog &defaultPriority(uint16_t pri = LOGLEVEL_KERN);
|
||||||
|
Syslog &logMask(uint8_t priMask);
|
||||||
|
|
||||||
|
void enable();
|
||||||
|
void disable();
|
||||||
|
bool isEnabled();
|
||||||
|
|
||||||
|
bool vlogf(uint16_t pri, const char *fmt, va_list args) __attribute__((format(printf, 3, 0)));
|
||||||
|
bool vlogf(uint16_t pri, const char *appName, const char *fmt, va_list args) __attribute__((format(printf, 3, 0)));
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HAS_ETHERNET || HAS_WIFI
|
||||||
|
|
||||||
|
#endif // SYSLOG_H
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* @file FSCommon.cpp
|
||||||
|
* @brief This file contains functions for common filesystem operations such as copying, renaming, listing and deleting files and
|
||||||
|
* directories.
|
||||||
|
*
|
||||||
|
* The functions in this file are used to perform common filesystem operations such as copying, renaming, listing and deleting
|
||||||
|
* files and directories. These functions are used in the Meshtastic-device project to manage files and directories on the
|
||||||
|
* device's filesystem.
|
||||||
|
*
|
||||||
|
*/
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
@@ -8,10 +18,19 @@
|
|||||||
#ifdef SDCARD_USE_SPI1
|
#ifdef SDCARD_USE_SPI1
|
||||||
SPIClass SPI1(HSPI);
|
SPIClass SPI1(HSPI);
|
||||||
#define SDHandler SPI1
|
#define SDHandler SPI1
|
||||||
|
#else
|
||||||
|
#define SDHandler SPI
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // HAS_SDCARD
|
#endif // HAS_SDCARD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copies a file from one location to another.
|
||||||
|
*
|
||||||
|
* @param from The path of the source file.
|
||||||
|
* @param to The path of the destination file.
|
||||||
|
* @return true if the file was successfully copied, false otherwise.
|
||||||
|
*/
|
||||||
bool copyFile(const char *from, const char *to)
|
bool copyFile(const char *from, const char *to)
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
@@ -34,12 +53,21 @@ bool copyFile(const char *from, const char *to)
|
|||||||
f2.write(cbuffer, i);
|
f2.write(cbuffer, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f2.flush();
|
||||||
f2.close();
|
f2.close();
|
||||||
f1.close();
|
f1.close();
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renames a file from pathFrom to pathTo.
|
||||||
|
*
|
||||||
|
* @param pathFrom The original path of the file.
|
||||||
|
* @param pathTo The new path of the file.
|
||||||
|
*
|
||||||
|
* @return True if the file was successfully renamed, false otherwise.
|
||||||
|
*/
|
||||||
bool renameFile(const char *pathFrom, const char *pathTo)
|
bool renameFile(const char *pathFrom, const char *pathTo)
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
@@ -56,7 +84,14 @@ bool renameFile(const char *pathFrom, const char *pathTo)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void listDir(const char *dirname, uint8_t levels, boolean del = false)
|
/**
|
||||||
|
* Lists the contents of a directory.
|
||||||
|
*
|
||||||
|
* @param dirname The name of the directory to list.
|
||||||
|
* @param levels The number of levels of subdirectories to list.
|
||||||
|
* @param del Whether or not to delete the contents of the directory after listing.
|
||||||
|
*/
|
||||||
|
void listDir(const char *dirname, uint8_t levels, bool del = false)
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||||
@@ -151,6 +186,13 @@ void listDir(const char *dirname, uint8_t levels, boolean del = false)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a directory and all its contents.
|
||||||
|
*
|
||||||
|
* This function recursively removes a directory and all its contents, including subdirectories and files.
|
||||||
|
*
|
||||||
|
* @param dirname The name of the directory to remove.
|
||||||
|
*/
|
||||||
void rmDir(const char *dirname)
|
void rmDir(const char *dirname)
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
@@ -179,6 +221,9 @@ void fsInit()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the SD card and mounts the file system.
|
||||||
|
*/
|
||||||
void setupSDCard()
|
void setupSDCard()
|
||||||
{
|
{
|
||||||
#ifdef HAS_SDCARD
|
#ifdef HAS_SDCARD
|
||||||
@@ -209,4 +254,4 @@ void setupSDCard()
|
|||||||
LOG_DEBUG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
|
LOG_DEBUG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
|
||||||
LOG_DEBUG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
|
LOG_DEBUG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,13 @@
|
|||||||
#define FILE_O_READ "r"
|
#define FILE_O_READ "r"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARCH_STM32WL)
|
||||||
|
#include "platform/stm32wl/InternalFileSystem.h" // STM32WL version
|
||||||
|
#define FSCom InternalFS
|
||||||
|
#define FSBegin() FSCom.begin()
|
||||||
|
using namespace LittleFS_Namespace;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(ARCH_RP2040)
|
#if defined(ARCH_RP2040)
|
||||||
// RP2040
|
// RP2040
|
||||||
#include "LittleFS.h"
|
#include "LittleFS.h"
|
||||||
@@ -42,6 +49,6 @@ using namespace Adafruit_LittleFS_Namespace;
|
|||||||
void fsInit();
|
void fsInit();
|
||||||
bool copyFile(const char *from, const char *to);
|
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, bool del);
|
||||||
void rmDir(const char *dirname);
|
void rmDir(const char *dirname);
|
||||||
void setupSDCard();
|
void setupSDCard();
|
||||||
@@ -55,7 +55,7 @@ class GPSStatus : public Status
|
|||||||
#ifdef GPS_EXTRAVERBOSE
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
LOG_WARN("Using fixed latitude\n");
|
LOG_WARN("Using fixed latitude\n");
|
||||||
#endif
|
#endif
|
||||||
meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||||
return node->position.latitude_i;
|
return node->position.latitude_i;
|
||||||
} else {
|
} else {
|
||||||
return p.latitude_i;
|
return p.latitude_i;
|
||||||
@@ -68,7 +68,7 @@ class GPSStatus : public Status
|
|||||||
#ifdef GPS_EXTRAVERBOSE
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
LOG_WARN("Using fixed longitude\n");
|
LOG_WARN("Using fixed longitude\n");
|
||||||
#endif
|
#endif
|
||||||
meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||||
return node->position.longitude_i;
|
return node->position.longitude_i;
|
||||||
} else {
|
} else {
|
||||||
return p.longitude_i;
|
return p.longitude_i;
|
||||||
@@ -81,7 +81,7 @@ class GPSStatus : public Status
|
|||||||
#ifdef GPS_EXTRAVERBOSE
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
LOG_WARN("Using fixed altitude\n");
|
LOG_WARN("Using fixed altitude\n");
|
||||||
#endif
|
#endif
|
||||||
meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||||
return node->position.altitude;
|
return node->position.altitude;
|
||||||
} else {
|
} else {
|
||||||
return p.altitude;
|
return p.altitude;
|
||||||
@@ -106,7 +106,7 @@ class GPSStatus : public Status
|
|||||||
bool matches(const GPSStatus *newStatus) const
|
bool matches(const GPSStatus *newStatus) const
|
||||||
{
|
{
|
||||||
#ifdef GPS_EXTRAVERBOSE
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp);
|
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.timestamp, p.timestamp);
|
||||||
#endif
|
#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->isPowerSaving != isPowerSaving || newStatus->p.latitude_i != p.latitude_i ||
|
||||||
@@ -138,8 +138,9 @@ class GPSStatus : public Status
|
|||||||
LOG_DEBUG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp,
|
LOG_DEBUG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp,
|
||||||
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
||||||
p.ground_speed * 1e-2, p.sats_in_view);
|
p.ground_speed * 1e-2, p.sats_in_view);
|
||||||
} else
|
} else {
|
||||||
LOG_DEBUG("No GPS lock\n");
|
LOG_DEBUG("No GPS lock\n");
|
||||||
|
}
|
||||||
onNewStatus.notifyObservers(this);
|
onNewStatus.notifyObservers(this);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -148,4 +149,4 @@ class GPSStatus : public Status
|
|||||||
|
|
||||||
} // namespace meshtastic
|
} // namespace meshtastic
|
||||||
|
|
||||||
extern meshtastic::GPSStatus *gpsStatus;
|
extern meshtastic::GPSStatus *gpsStatus;
|
||||||
@@ -5,7 +5,8 @@
|
|||||||
* Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR)
|
* Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR)
|
||||||
*
|
*
|
||||||
* NOTE! xTimerPend... seems to ignore the time passed in on ESP32 and on NRF52
|
* NOTE! xTimerPend... seems to ignore the time passed in on ESP32 and on NRF52
|
||||||
* The reason this didn't work is bcause xTimerPednFunctCall really isn't a timer function at all - it just means run the callback
|
* The reason this didn't work is because xTimerPednFunctCall really isn't a timer function at all - it just means run the
|
||||||
|
callback
|
||||||
* from the timer thread the next time you have spare cycles.
|
* from the timer thread the next time you have spare cycles.
|
||||||
*
|
*
|
||||||
* @return true if successful, false if the timer fifo is too full.
|
* @return true if successful, false if the timer fifo is too full.
|
||||||
@@ -28,6 +29,16 @@ static void IRAM_ATTR onTimer()
|
|||||||
(*tCallback)(tParam1, tParam2);
|
(*tCallback)(tParam1, tParam2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules a hardware callback function to be executed after a specified delay.
|
||||||
|
*
|
||||||
|
* @param callback The function to be executed.
|
||||||
|
* @param param1 The first parameter to be passed to the function.
|
||||||
|
* @param param2 The second parameter to be passed to the function.
|
||||||
|
* @param delayMsec The delay time in milliseconds before the function is executed.
|
||||||
|
*
|
||||||
|
* @return True if the function was successfully scheduled, false otherwise.
|
||||||
|
*/
|
||||||
bool scheduleHWCallback(PendableFunction callback, void *param1, uint32_t param2, uint32_t delayMsec)
|
bool scheduleHWCallback(PendableFunction callback, void *param1, uint32_t param2, uint32_t delayMsec)
|
||||||
{
|
{
|
||||||
if (!timer) {
|
if (!timer) {
|
||||||
|
|||||||
383
src/Power.cpp
383
src/Power.cpp
@@ -1,11 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* @file Power.cpp
|
||||||
|
* @brief This file contains the implementation of the Power class, which is responsible for managing power-related functionality
|
||||||
|
* of the device. It includes battery level sensing, power management unit (PMU) control, and power state machine management. The
|
||||||
|
* Power class is used by the main device class to manage power-related functionality.
|
||||||
|
*
|
||||||
|
* The file also includes implementations of various battery level sensors, such as the AnalogBatteryLevel class, which assumes
|
||||||
|
* the battery voltage is attached via a voltage-divider to an analog input.
|
||||||
|
*
|
||||||
|
* This file is part of the Meshtastic project.
|
||||||
|
* For more information, see: https://meshtastic.org/
|
||||||
|
*/
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "buzz/buzz.h"
|
#include "buzz/buzz.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "meshUtils.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "utils.h"
|
|
||||||
|
#ifdef DEBUG_HEAP_MQTT
|
||||||
|
#include "mqtt/MQTT.h"
|
||||||
|
#include "target_specific.h"
|
||||||
|
#include <WiFi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DELAY_FOREVER
|
||||||
|
#define DELAY_FOREVER portMAX_DELAY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BATTERY_PIN) && defined(ARCH_ESP32)
|
||||||
|
|
||||||
|
#ifndef BAT_MEASURE_ADC_UNIT // ADC1 is default
|
||||||
|
static const adc1_channel_t adc_channel = ADC_CHANNEL;
|
||||||
|
static const adc_unit_t unit = ADC_UNIT_1;
|
||||||
|
#else // ADC2
|
||||||
|
static const adc2_channel_t adc_channel = ADC_CHANNEL;
|
||||||
|
static const adc_unit_t unit = ADC_UNIT_2;
|
||||||
|
RTC_NOINIT_ATTR uint64_t RTC_reg_b;
|
||||||
|
|
||||||
|
#endif // BAT_MEASURE_ADC_UNIT
|
||||||
|
|
||||||
|
esp_adc_cal_characteristics_t *adc_characs = (esp_adc_cal_characteristics_t *)calloc(1, sizeof(esp_adc_cal_characteristics_t));
|
||||||
|
#ifndef ADC_ATTENUATION
|
||||||
|
static const adc_atten_t atten = ADC_ATTEN_DB_11;
|
||||||
|
#else
|
||||||
|
static const adc_atten_t atten = ADC_ATTENUATION;
|
||||||
|
#endif
|
||||||
|
#endif // BATTERY_PIN && ARCH_ESP32
|
||||||
|
|
||||||
|
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
|
||||||
|
INA260Sensor ina260Sensor;
|
||||||
|
INA219Sensor ina219Sensor;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_PMU
|
#ifdef HAS_PMU
|
||||||
#include "XPowersAXP192.tpp"
|
#include "XPowersAXP192.tpp"
|
||||||
@@ -13,8 +60,9 @@
|
|||||||
#include "XPowersLibInterface.hpp"
|
#include "XPowersLibInterface.hpp"
|
||||||
XPowersLibInterface *PMU = NULL;
|
XPowersLibInterface *PMU = NULL;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Copy of the base class defined in axp20x.h.
|
// Copy of the base class defined in axp20x.h.
|
||||||
// I'd rather not inlude axp20x.h as it brings Wire dependency.
|
// I'd rather not include axp20x.h as it brings Wire dependency.
|
||||||
class HasBatteryLevel
|
class HasBatteryLevel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -98,6 +146,13 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
virtual uint16_t getBattVoltage() override
|
virtual uint16_t getBattVoltage() override
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
|
||||||
|
if (hasINA()) {
|
||||||
|
LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address);
|
||||||
|
return getINAVoltage();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ADC_MULTIPLIER
|
#ifndef ADC_MULTIPLIER
|
||||||
#define ADC_MULTIPLIER 2.0
|
#define ADC_MULTIPLIER 2.0
|
||||||
#endif
|
#endif
|
||||||
@@ -118,18 +173,41 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
// Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic
|
// Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic
|
||||||
// environment.
|
// environment.
|
||||||
uint32_t raw = 0;
|
uint32_t raw = 0;
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
|
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
|
||||||
|
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
|
||||||
|
raw += adc1_get_raw(adc_channel);
|
||||||
|
}
|
||||||
|
#else // ADC2
|
||||||
|
int32_t adc_buf = 0;
|
||||||
|
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
|
||||||
|
// ADC2 wifi bug workaround, see
|
||||||
|
// https://github.com/espressif/arduino-esp32/issues/102
|
||||||
|
WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, RTC_reg_b);
|
||||||
|
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
|
||||||
|
adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf);
|
||||||
|
raw += adc_buf;
|
||||||
|
}
|
||||||
|
#endif // BAT_MEASURE_ADC_UNIT
|
||||||
|
#else // !ARCH_ESP32
|
||||||
for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
|
for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
|
||||||
raw += analogRead(BATTERY_PIN);
|
raw += analogRead(BATTERY_PIN);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
raw = raw / BATTERY_SENSE_SAMPLES;
|
raw = raw / BATTERY_SENSE_SAMPLES;
|
||||||
|
|
||||||
float scaled;
|
float scaled;
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
|
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
|
||||||
|
scaled *= operativeAdcMultiplier;
|
||||||
|
#else
|
||||||
#ifndef VBAT_RAW_TO_SCALED
|
#ifndef VBAT_RAW_TO_SCALED
|
||||||
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
|
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
|
||||||
#else
|
#else
|
||||||
scaled = VBAT_RAW_TO_SCALED(raw); // defined in variant.h
|
scaled = VBAT_RAW_TO_SCALED(raw); // defined in variant.h
|
||||||
#endif
|
#endif // VBAT RAW TO SCALED
|
||||||
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
|
#endif // ARCH_ESP32
|
||||||
|
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
|
||||||
|
|
||||||
last_read_value = scaled;
|
last_read_value = scaled;
|
||||||
return scaled;
|
return scaled;
|
||||||
} else {
|
} else {
|
||||||
@@ -137,30 +215,34 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif // BATTERY_PIN
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return true if there is a battery installed in this unit
|
* return true if there is a battery installed in this unit
|
||||||
*/
|
*/
|
||||||
virtual bool isBatteryConnect() override
|
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
|
||||||
{
|
|
||||||
return getBatteryPercent() != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||||
/// in power
|
/// in power
|
||||||
|
/// On some boards we don't have the power management chip (like AXPxxxx)
|
||||||
|
/// so we use EXT_PWR_DETECT GPIO pin to detect external power source
|
||||||
virtual bool isVbusIn() override
|
virtual bool isVbusIn() override
|
||||||
{
|
{
|
||||||
|
#ifdef EXT_PWR_DETECT
|
||||||
|
// if external powered that pin will be pulled up
|
||||||
|
if (digitalRead(EXT_PWR_DETECT) == HIGH) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// if it's not HIGH - check the battery
|
||||||
|
#endif
|
||||||
|
|
||||||
return getBattVoltage() > chargingVolt;
|
return getBattVoltage() > chargingVolt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assume charging if we have a battery and external power is connected.
|
/// Assume charging if we have a battery and external power is connected.
|
||||||
/// we can't be smart enough to say 'full'?
|
/// we can't be smart enough to say 'full'?
|
||||||
virtual bool isCharging() override
|
virtual bool isCharging() override { return isBatteryConnect() && isVbusIn(); }
|
||||||
{
|
|
||||||
return isBatteryConnect() && isVbusIn();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||||
@@ -183,6 +265,35 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
const float fullVolt = BAT_FULLVOLT, emptyVolt = BAT_EMPTYVOLT, chargingVolt = BAT_CHARGINGVOLT, noBatVolt = BAT_NOBATVOLT;
|
const float fullVolt = BAT_FULLVOLT, emptyVolt = BAT_EMPTYVOLT, chargingVolt = BAT_CHARGINGVOLT, noBatVolt = BAT_NOBATVOLT;
|
||||||
float last_read_value = 0.0;
|
float last_read_value = 0.0;
|
||||||
uint32_t last_read_time_ms = 0;
|
uint32_t last_read_time_ms = 0;
|
||||||
|
|
||||||
|
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO)
|
||||||
|
uint16_t getINAVoltage()
|
||||||
|
{
|
||||||
|
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
|
||||||
|
return ina219Sensor.getBusVoltageMv();
|
||||||
|
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
|
||||||
|
return ina260Sensor.getBusVoltageMv();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasINA()
|
||||||
|
{
|
||||||
|
if (!config.power.device_battery_ina_address) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
|
||||||
|
if (!ina219Sensor.isInitialized())
|
||||||
|
return ina219Sensor.runOnce() > 0;
|
||||||
|
return ina219Sensor.isRunning();
|
||||||
|
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
|
||||||
|
if (!ina260Sensor.isInitialized())
|
||||||
|
return ina260Sensor.runOnce() > 0;
|
||||||
|
return ina260Sensor.isRunning();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
AnalogBatteryLevel analogLevel;
|
AnalogBatteryLevel analogLevel;
|
||||||
@@ -192,37 +303,68 @@ Power::Power() : OSThread("Power")
|
|||||||
statusHandler = {};
|
statusHandler = {};
|
||||||
low_voltage_counter = 0;
|
low_voltage_counter = 0;
|
||||||
#ifdef DEBUG_HEAP
|
#ifdef DEBUG_HEAP
|
||||||
lastheap = ESP.getFreeHeap();
|
lastheap = memGet.getFreeHeap();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Power::analogInit()
|
bool Power::analogInit()
|
||||||
{
|
{
|
||||||
|
#ifdef EXT_PWR_DETECT
|
||||||
|
pinMode(EXT_PWR_DETECT, INPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BATTERY_PIN
|
#ifdef BATTERY_PIN
|
||||||
LOG_DEBUG("Using analog input %d for battery level\n", BATTERY_PIN);
|
LOG_DEBUG("Using analog input %d for battery level\n", BATTERY_PIN);
|
||||||
|
|
||||||
// disable any internal pullups
|
// disable any internal pullups
|
||||||
pinMode(BATTERY_PIN, INPUT);
|
pinMode(BATTERY_PIN, INPUT);
|
||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifndef BATTERY_SENSE_RESOLUTION_BITS
|
||||||
// ESP32 needs special analog stuff
|
#define BATTERY_SENSE_RESOLUTION_BITS 10
|
||||||
adcAttachPin(BATTERY_PIN);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARCH_ESP32 // ESP32 needs special analog stuff
|
||||||
|
|
||||||
|
#ifndef ADC_WIDTH // max resolution by default
|
||||||
|
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
|
||||||
|
#else
|
||||||
|
static const adc_bits_width_t width = ADC_WIDTH;
|
||||||
|
#endif
|
||||||
|
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
|
||||||
|
adc1_config_width(width);
|
||||||
|
adc1_config_channel_atten(adc_channel, atten);
|
||||||
|
#else // ADC2
|
||||||
|
adc2_config_channel_atten(adc_channel, atten);
|
||||||
|
// ADC2 wifi bug workaround
|
||||||
|
RTC_reg_b = READ_PERI_REG(SENS_SAR_READ_CTRL2_REG);
|
||||||
|
#endif
|
||||||
|
// calibrate ADC
|
||||||
|
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_characs);
|
||||||
|
// show ADC characterization base
|
||||||
|
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||||
|
LOG_INFO("ADCmod: ADC characterization based on Two Point values stored in eFuse\n");
|
||||||
|
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
||||||
|
LOG_INFO("ADCmod: ADC characterization based on reference voltage stored in eFuse\n");
|
||||||
|
} else {
|
||||||
|
LOG_INFO("ADCmod: ADC characterization based on default reference voltage\n");
|
||||||
|
}
|
||||||
|
#if defined(HELTEC_V3) || defined(HELTEC_WSL_V3)
|
||||||
|
pinMode(37, OUTPUT); // needed for P channel mosfet to work
|
||||||
|
digitalWrite(37, LOW);
|
||||||
|
#endif
|
||||||
|
#endif // ARCH_ESP32
|
||||||
|
|
||||||
#ifdef ARCH_NRF52
|
#ifdef ARCH_NRF52
|
||||||
#ifdef VBAT_AR_INTERNAL
|
#ifdef VBAT_AR_INTERNAL
|
||||||
analogReference(VBAT_AR_INTERNAL);
|
analogReference(VBAT_AR_INTERNAL);
|
||||||
#else
|
#else
|
||||||
analogReference(AR_INTERNAL); // 3.6V
|
analogReference(AR_INTERNAL); // 3.6V
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef BATTERY_SENSE_RESOLUTION_BITS
|
|
||||||
#define BATTERY_SENSE_RESOLUTION_BITS 10
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// adcStart(BATTERY_PIN);
|
|
||||||
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11
|
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11
|
||||||
// depending on needed resolution.
|
// depending on needed resolution.
|
||||||
|
|
||||||
|
#endif // ARCH_NRF52
|
||||||
|
|
||||||
batteryLevel = &analogLevel;
|
batteryLevel = &analogLevel;
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
@@ -230,6 +372,11 @@ bool Power::analogInit()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Power class.
|
||||||
|
*
|
||||||
|
* @return true if the setup was successful, false otherwise.
|
||||||
|
*/
|
||||||
bool Power::setup()
|
bool Power::setup()
|
||||||
{
|
{
|
||||||
bool found = axpChipInit();
|
bool found = axpChipInit();
|
||||||
@@ -250,16 +397,23 @@ void Power::shutdown()
|
|||||||
digitalWrite(PIN_EINK_EN, LOW); // power off backlight first
|
digitalWrite(PIN_EINK_EN, LOW); // power off backlight first
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_PMU
|
|
||||||
LOG_INFO("Shutting down\n");
|
LOG_INFO("Shutting down\n");
|
||||||
if (PMU) {
|
|
||||||
|
#ifdef HAS_PMU
|
||||||
|
if (pmu_found == true) {
|
||||||
PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
|
PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
|
||||||
PMU->shutdown();
|
PMU->shutdown();
|
||||||
}
|
}
|
||||||
#elif defined(ARCH_NRF52)
|
#elif defined(ARCH_NRF52) || defined(ARCH_ESP32)
|
||||||
playBeep();
|
#ifdef PIN_LED1
|
||||||
ledOff(PIN_LED1);
|
ledOff(PIN_LED1);
|
||||||
|
#endif
|
||||||
|
#ifdef PIN_LED2
|
||||||
ledOff(PIN_LED2);
|
ledOff(PIN_LED2);
|
||||||
|
#endif
|
||||||
|
#ifdef PIN_LED3
|
||||||
|
ledOff(PIN_LED2);
|
||||||
|
#endif
|
||||||
doDeepSleep(DELAY_FOREVER);
|
doDeepSleep(DELAY_FOREVER);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -271,7 +425,7 @@ void Power::readPowerStatus()
|
|||||||
{
|
{
|
||||||
if (batteryLevel) {
|
if (batteryLevel) {
|
||||||
bool hasBattery = batteryLevel->isBatteryConnect();
|
bool hasBattery = batteryLevel->isBatteryConnect();
|
||||||
int batteryVoltageMv = 0;
|
uint32_t batteryVoltageMv = 0;
|
||||||
int8_t batteryChargePercent = 0;
|
int8_t batteryChargePercent = 0;
|
||||||
if (hasBattery) {
|
if (hasBattery) {
|
||||||
batteryVoltageMv = batteryLevel->getBattVoltage();
|
batteryVoltageMv = batteryLevel->getBattVoltage();
|
||||||
@@ -296,7 +450,7 @@ void Power::readPowerStatus()
|
|||||||
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
|
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
|
||||||
newStatus.notifyObservers(&powerStatus2);
|
newStatus.notifyObservers(&powerStatus2);
|
||||||
#ifdef DEBUG_HEAP
|
#ifdef DEBUG_HEAP
|
||||||
if (lastheap != ESP.getFreeHeap()) {
|
if (lastheap != memGet.getFreeHeap()) {
|
||||||
LOG_DEBUG("Threads running:");
|
LOG_DEBUG("Threads running:");
|
||||||
int running = 0;
|
int running = 0;
|
||||||
for (int i = 0; i < MAX_THREADS; i++) {
|
for (int i = 0; i < MAX_THREADS; i++) {
|
||||||
@@ -307,33 +461,52 @@ void Power::readPowerStatus()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_DEBUG("\n");
|
LOG_DEBUG("\n");
|
||||||
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", ESP.getFreeHeap(), ESP.getHeapSize(),
|
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", memGet.getFreeHeap(), memGet.getHeapSize(),
|
||||||
ESP.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
||||||
lastheap = ESP.getFreeHeap();
|
lastheap = memGet.getFreeHeap();
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_HEAP_MQTT
|
||||||
|
if (mqtt) {
|
||||||
|
// send MQTT-Packet with Heap-Size
|
||||||
|
uint8_t dmac[6];
|
||||||
|
getMacAddr(dmac); // Get our hardware ID
|
||||||
|
char mac[18];
|
||||||
|
sprintf(mac, "!%02x%02x%02x%02x", dmac[2], dmac[3], dmac[4], dmac[5]);
|
||||||
|
|
||||||
|
auto newHeap = memGet.getFreeHeap();
|
||||||
|
std::string heapTopic =
|
||||||
|
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/heap/") + std::string(mac);
|
||||||
|
std::string heapString = std::to_string(newHeap);
|
||||||
|
mqtt->pubSub.publish(heapTopic.c_str(), heapString.c_str(), false);
|
||||||
|
auto wifiRSSI = WiFi.RSSI();
|
||||||
|
std::string wifiTopic =
|
||||||
|
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/wifi/") + std::string(mac);
|
||||||
|
std::string wifiString = std::to_string(wifiRSSI);
|
||||||
|
mqtt->pubSub.publish(wifiTopic.c_str(), wifiString.c_str(), false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
|
#endif
|
||||||
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
|
|
||||||
#ifdef ARCH_NRF52
|
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 10 low readings in
|
||||||
|
// a row
|
||||||
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
|
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
|
||||||
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) {
|
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) {
|
||||||
low_voltage_counter++;
|
low_voltage_counter++;
|
||||||
LOG_DEBUG("Warning RAK4631 Low voltage counter: %d/10\n", low_voltage_counter);
|
LOG_DEBUG("Low voltage counter: %d/10\n", low_voltage_counter);
|
||||||
if (low_voltage_counter > 10) {
|
if (low_voltage_counter > 10) {
|
||||||
|
#ifdef ARCH_NRF52
|
||||||
// We can't trigger deep sleep on NRF52, it's freezing the board
|
// We can't trigger deep sleep on NRF52, it's freezing the board
|
||||||
// powerFSM.trigger(EVENT_LOW_BATTERY);
|
|
||||||
LOG_DEBUG("Low voltage detected, but not triggering deep sleep\n");
|
LOG_DEBUG("Low voltage detected, but not triggering deep sleep\n");
|
||||||
|
#else
|
||||||
|
LOG_INFO("Low voltage detected, triggering deep sleep\n");
|
||||||
|
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
low_voltage_counter = 0;
|
low_voltage_counter = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
// If we have a battery at all and it is less than 10% full, force deep sleep
|
|
||||||
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
|
|
||||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
// No power sensing on this board - tell everyone else we have no idea what is happening
|
// No power sensing on this board - tell everyone else we have no idea what is happening
|
||||||
const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
|
const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
|
||||||
@@ -378,10 +551,12 @@ int32_t Power::runOnce()
|
|||||||
LOG_DEBUG("Battery removed\n");
|
LOG_DEBUG("Battery removed\n");
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
#ifndef T_WATCH_S3 // FIXME - why is this triggering on the T-Watch S3?
|
||||||
if (PMU->isPekeyLongPressIrq()) {
|
if (PMU->isPekeyLongPressIrq()) {
|
||||||
LOG_DEBUG("PEK long button press\n");
|
LOG_DEBUG("PEK long button press\n");
|
||||||
screen->setOn(false);
|
screen->setOn(false);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
PMU->clearIrqStatus();
|
PMU->clearIrqStatus();
|
||||||
}
|
}
|
||||||
@@ -394,10 +569,10 @@ int32_t Power::runOnce()
|
|||||||
* Init the power manager chip
|
* Init the power manager chip
|
||||||
*
|
*
|
||||||
* axp192 power
|
* axp192 power
|
||||||
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the axp192
|
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the
|
||||||
share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this on!) LDO1
|
axp192 share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this
|
||||||
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
|
on!) LDO1 30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of
|
||||||
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
|
days), can not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
bool Power::axpChipInit()
|
bool Power::axpChipInit()
|
||||||
@@ -487,52 +662,90 @@ bool Power::axpChipInit()
|
|||||||
|
|
||||||
// Set up the charging voltage
|
// Set up the charging voltage
|
||||||
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
||||||
|
|
||||||
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
||||||
|
|
||||||
// t-beam s3 core
|
/*The alternative version of T-Beam 1.1 differs from T-Beam V1.1 in that it uses an AXP2101 power chip*/
|
||||||
|
if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) {
|
||||||
|
// Unuse power channel
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DCDC2);
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DCDC3);
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DCDC4);
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DCDC5);
|
||||||
|
PMU->disablePowerOutput(XPOWERS_ALDO1);
|
||||||
|
PMU->disablePowerOutput(XPOWERS_ALDO4);
|
||||||
|
PMU->disablePowerOutput(XPOWERS_BLDO1);
|
||||||
|
PMU->disablePowerOutput(XPOWERS_BLDO2);
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DLDO1);
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DLDO2);
|
||||||
|
|
||||||
/**
|
// GNSS RTC PowerVDD 3300mV
|
||||||
* gnss module power channel
|
PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
|
||||||
* The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during initialization
|
PMU->enablePowerOutput(XPOWERS_VBACKUP);
|
||||||
*/
|
|
||||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
|
|
||||||
PMU->enablePowerOutput(XPOWERS_ALDO4);
|
|
||||||
|
|
||||||
// lora radio power channel
|
// ESP32 VDD 3300mV
|
||||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
|
// ! No need to set, automatically open , Don't close it
|
||||||
PMU->enablePowerOutput(XPOWERS_ALDO3);
|
// PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
|
||||||
|
// PMU->setProtectedChannel(XPOWERS_DCDC1);
|
||||||
|
|
||||||
// m.2 interface
|
// LoRa VDD 3300mV
|
||||||
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
|
||||||
PMU->enablePowerOutput(XPOWERS_DCDC3);
|
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||||
|
|
||||||
/**
|
// GNSS VDD 3300mV
|
||||||
* ALDO2 cannot be turned off.
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
|
||||||
* It is a necessary condition for sensor communication.
|
PMU->enablePowerOutput(XPOWERS_ALDO3);
|
||||||
* It must be turned on to properly access the sensor and screen
|
} else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE ||
|
||||||
* It is also responsible for the power supply of PCF8563
|
HW_VENDOR == meshtastic_HardwareModel_T_WATCH_S3) {
|
||||||
*/
|
// t-beam s3 core
|
||||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
|
/**
|
||||||
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
* gnss module power channel
|
||||||
|
* The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during
|
||||||
|
* initialization
|
||||||
|
*/
|
||||||
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
|
||||||
|
PMU->enablePowerOutput(XPOWERS_ALDO4);
|
||||||
|
|
||||||
// 6-axis , magnetometer ,bme280 , oled screen power channel
|
// lora radio power channel
|
||||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
|
||||||
PMU->enablePowerOutput(XPOWERS_ALDO1);
|
PMU->enablePowerOutput(XPOWERS_ALDO3);
|
||||||
|
|
||||||
// sdcard power channle
|
// m.2 interface
|
||||||
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
|
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
|
||||||
PMU->enablePowerOutput(XPOWERS_BLDO1);
|
PMU->enablePowerOutput(XPOWERS_DCDC3);
|
||||||
|
|
||||||
// PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
|
/**
|
||||||
// PMU->enablePowerOutput(XPOWERS_DCDC4);
|
* ALDO2 cannot be turned off.
|
||||||
|
* It is a necessary condition for sensor communication.
|
||||||
|
* It must be turned on to properly access the sensor and screen
|
||||||
|
* It is also responsible for the power supply of PCF8563
|
||||||
|
*/
|
||||||
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
|
||||||
|
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||||
|
|
||||||
// not use channel
|
// 6-axis , magnetometer ,bme280 , oled screen power channel
|
||||||
PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
|
||||||
PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited
|
PMU->enablePowerOutput(XPOWERS_ALDO1);
|
||||||
PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist
|
|
||||||
PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist
|
// sdcard power channel
|
||||||
PMU->disablePowerOutput(XPOWERS_VBACKUP);
|
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
|
||||||
|
PMU->enablePowerOutput(XPOWERS_BLDO1);
|
||||||
|
|
||||||
|
#ifdef T_WATCH_S3
|
||||||
|
// DRV2605 power channel
|
||||||
|
PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
|
||||||
|
PMU->enablePowerOutput(XPOWERS_BLDO2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
|
||||||
|
// PMU->enablePowerOutput(XPOWERS_DCDC4);
|
||||||
|
|
||||||
|
// not use channel
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist
|
||||||
|
PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist
|
||||||
|
PMU->disablePowerOutput(XPOWERS_VBACKUP);
|
||||||
|
}
|
||||||
|
|
||||||
// disable all axp chip interrupt
|
// disable all axp chip interrupt
|
||||||
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
|
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
|
||||||
@@ -646,4 +859,4 @@ bool Power::axpChipInit()
|
|||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* @file PowerFSM.cpp
|
||||||
|
* @brief Implements the finite state machine for power management.
|
||||||
|
*
|
||||||
|
* This file contains the implementation of the finite state machine (FSM) for power management.
|
||||||
|
* The FSM controls the power states of the device, including SDS (shallow deep sleep), LS (light sleep),
|
||||||
|
* NB (normal mode), and POWER (powered mode). The FSM also handles transitions between states and
|
||||||
|
* actions to be taken upon entering or exiting each state.
|
||||||
|
*/
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
@@ -26,13 +35,16 @@ static bool isPowered()
|
|||||||
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
|
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
|
||||||
|
|
||||||
2) If we detect USB power from the power management chip, we must be getting power externally.
|
2) If we detect USB power from the power management chip, we must be getting power externally.
|
||||||
|
|
||||||
|
3) On some boards we don't have the power management chip (like AXPxxxx) so we use EXT_PWR_DETECT GPIO pin to detect
|
||||||
|
external power source (see `isVbusIn()` in `Power.cpp`)
|
||||||
*/
|
*/
|
||||||
return !isPowerSavingMode && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
return !isPowerSavingMode && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdsEnter()
|
static void sdsEnter()
|
||||||
{
|
{
|
||||||
LOG_INFO("Enter state: SDS\n");
|
LOG_DEBUG("Enter state: SDS\n");
|
||||||
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
||||||
doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs));
|
doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs));
|
||||||
}
|
}
|
||||||
@@ -41,7 +53,7 @@ extern Power *power;
|
|||||||
|
|
||||||
static void shutdownEnter()
|
static void shutdownEnter()
|
||||||
{
|
{
|
||||||
LOG_INFO("Enter state: SHUTDOWN\n");
|
LOG_DEBUG("Enter state: SHUTDOWN\n");
|
||||||
power->shutdown();
|
power->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,11 +78,11 @@ static void lsIdle()
|
|||||||
|
|
||||||
// Do we have more sleeping to do?
|
// Do we have more sleeping to do?
|
||||||
if (secsSlept < config.power.ls_secs) {
|
if (secsSlept < config.power.ls_secs) {
|
||||||
// Briefly come out of sleep long enough to blink the led once every few seconds
|
|
||||||
uint32_t sleepTime = 30;
|
|
||||||
|
|
||||||
// If some other service would stall sleep, don't let sleep happen yet
|
// If some other service would stall sleep, don't let sleep happen yet
|
||||||
if (doPreflightSleep()) {
|
if (doPreflightSleep()) {
|
||||||
|
// Briefly come out of sleep long enough to blink the led once every few seconds
|
||||||
|
uint32_t sleepTime = 30;
|
||||||
|
|
||||||
setLed(false); // Never leave led on while in light sleep
|
setLed(false); // Never leave led on while in light sleep
|
||||||
esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL);
|
esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL);
|
||||||
|
|
||||||
@@ -78,8 +90,8 @@ static void lsIdle()
|
|||||||
case ESP_SLEEP_WAKEUP_TIMER:
|
case ESP_SLEEP_WAKEUP_TIMER:
|
||||||
// Normal case: timer expired, we should just go back to sleep ASAP
|
// Normal case: timer expired, we should just go back to sleep ASAP
|
||||||
|
|
||||||
setLed(true); // briefly turn on led
|
setLed(true); // briefly turn on led
|
||||||
wakeCause2 = doLightSleep(1); // leave led on for 1ms
|
wakeCause2 = doLightSleep(100); // leave led on for 1ms
|
||||||
|
|
||||||
secsSlept += sleepTime;
|
secsSlept += sleepTime;
|
||||||
// LOG_INFO("sleeping, flash led!\n");
|
// LOG_INFO("sleeping, flash led!\n");
|
||||||
@@ -96,12 +108,11 @@ static void lsIdle()
|
|||||||
LOG_INFO("wakeCause2 %d\n", wakeCause2);
|
LOG_INFO("wakeCause2 %d\n", wakeCause2);
|
||||||
|
|
||||||
#ifdef BUTTON_PIN
|
#ifdef BUTTON_PIN
|
||||||
bool pressed = !digitalRead(BUTTON_PIN);
|
bool pressed = !digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
|
||||||
#else
|
#else
|
||||||
bool pressed = false;
|
bool pressed = false;
|
||||||
#endif
|
#endif
|
||||||
if (pressed) // If we woke because of press, instead generate a PRESS event.
|
if (pressed) { // If we woke because of press, instead generate a PRESS event.
|
||||||
{
|
|
||||||
powerFSM.trigger(EVENT_PRESS);
|
powerFSM.trigger(EVENT_PRESS);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
|
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
|
||||||
@@ -133,9 +144,12 @@ static void lsExit()
|
|||||||
|
|
||||||
static void nbEnter()
|
static void nbEnter()
|
||||||
{
|
{
|
||||||
LOG_INFO("Enter state: NB\n");
|
LOG_DEBUG("Enter state: NB\n");
|
||||||
screen->setOn(false);
|
screen->setOn(false);
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
|
// Only ESP32 should turn off bluetooth
|
||||||
setBluetoothEnable(false);
|
setBluetoothEnable(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
// FIXME - check if we already have packets for phone and immediately trigger EVENT_PACKETS_FOR_PHONE
|
// FIXME - check if we already have packets for phone and immediately trigger EVENT_PACKETS_FOR_PHONE
|
||||||
}
|
}
|
||||||
@@ -148,7 +162,7 @@ static void darkEnter()
|
|||||||
|
|
||||||
static void serialEnter()
|
static void serialEnter()
|
||||||
{
|
{
|
||||||
LOG_INFO("Enter state: SERIAL\n");
|
LOG_DEBUG("Enter state: SERIAL\n");
|
||||||
setBluetoothEnable(false);
|
setBluetoothEnable(false);
|
||||||
screen->setOn(true);
|
screen->setOn(true);
|
||||||
screen->print("Serial connected\n");
|
screen->print("Serial connected\n");
|
||||||
@@ -156,12 +170,14 @@ static void serialEnter()
|
|||||||
|
|
||||||
static void serialExit()
|
static void serialExit()
|
||||||
{
|
{
|
||||||
|
// Turn bluetooth back on when we leave serial stream API
|
||||||
|
setBluetoothEnable(true);
|
||||||
screen->print("Serial disconnected\n");
|
screen->print("Serial disconnected\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void powerEnter()
|
static void powerEnter()
|
||||||
{
|
{
|
||||||
LOG_INFO("Enter state: POWER\n");
|
// LOG_DEBUG("Enter state: POWER\n");
|
||||||
if (!isPowered()) {
|
if (!isPowered()) {
|
||||||
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
|
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
|
||||||
LOG_INFO("Loss of power in Powered\n");
|
LOG_INFO("Loss of power in Powered\n");
|
||||||
@@ -169,7 +185,11 @@ static void powerEnter()
|
|||||||
} else {
|
} else {
|
||||||
screen->setOn(true);
|
screen->setOn(true);
|
||||||
setBluetoothEnable(true);
|
setBluetoothEnable(true);
|
||||||
screen->print("Powered...\n");
|
// within enter() the function getState() returns the state we came from
|
||||||
|
if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
|
||||||
|
strcmp(powerFSM.getState()->name, "DARK") != 0) {
|
||||||
|
screen->print("Powered...\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,25 +206,15 @@ static void powerExit()
|
|||||||
{
|
{
|
||||||
screen->setOn(true);
|
screen->setOn(true);
|
||||||
setBluetoothEnable(true);
|
setBluetoothEnable(true);
|
||||||
screen->print("Unpowered...\n");
|
if (!isPowered())
|
||||||
|
screen->print("Unpowered...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onEnter()
|
static void onEnter()
|
||||||
{
|
{
|
||||||
LOG_INFO("Enter state: ON\n");
|
LOG_DEBUG("Enter state: ON\n");
|
||||||
screen->setOn(true);
|
screen->setOn(true);
|
||||||
setBluetoothEnable(true);
|
setBluetoothEnable(true);
|
||||||
|
|
||||||
static uint32_t lastPingMs;
|
|
||||||
|
|
||||||
uint32_t now = millis();
|
|
||||||
|
|
||||||
if ((now - lastPingMs) >
|
|
||||||
30 * 1000) { // if more than a minute since our last press, ask node we are looking at to update their state
|
|
||||||
if (displayedNodeNum)
|
|
||||||
service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node
|
|
||||||
lastPingMs = now;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onIdle()
|
static void onIdle()
|
||||||
@@ -222,7 +232,7 @@ static void screenPress()
|
|||||||
|
|
||||||
static void bootEnter()
|
static void bootEnter()
|
||||||
{
|
{
|
||||||
LOG_INFO("Enter state: BOOT\n");
|
LOG_DEBUG("Enter state: BOOT\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN");
|
State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN");
|
||||||
@@ -246,7 +256,11 @@ void PowerFSM_setup()
|
|||||||
|
|
||||||
// wake timer expired or a packet arrived
|
// wake timer expired or a packet arrived
|
||||||
// if we are a router node, we go to NB (no need for bluetooth) otherwise we go to DARK (so we can send message to phone)
|
// if we are a router node, we go to NB (no need for bluetooth) otherwise we go to DARK (so we can send message to phone)
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
|
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
|
||||||
|
#else // Don't go into a no-bluetooth state on low power platforms
|
||||||
|
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
|
||||||
|
#endif
|
||||||
|
|
||||||
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from
|
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from
|
||||||
// light sleep we _always_ transition to NB or dark and
|
// light sleep we _always_ transition to NB or dark and
|
||||||
@@ -257,7 +271,7 @@ void PowerFSM_setup()
|
|||||||
// Handle press events - note: we ignore button presses when in API mode
|
// Handle press events - note: we ignore button presses when in API mode
|
||||||
powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press");
|
powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press");
|
||||||
powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press");
|
powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press");
|
||||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press");
|
powerFSM.add_transition(&stateDARK, isPowered() ? &statePOWER : &stateON, EVENT_PRESS, NULL, "Press");
|
||||||
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press");
|
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press");
|
||||||
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
|
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
|
||||||
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress,
|
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress,
|
||||||
@@ -283,7 +297,8 @@ void PowerFSM_setup()
|
|||||||
powerFSM.add_transition(&stateLS, &stateON, EVENT_INPUT, NULL, "Input Device");
|
powerFSM.add_transition(&stateLS, &stateON, EVENT_INPUT, NULL, "Input Device");
|
||||||
powerFSM.add_transition(&stateNB, &stateON, EVENT_INPUT, NULL, "Input Device");
|
powerFSM.add_transition(&stateNB, &stateON, EVENT_INPUT, NULL, "Input Device");
|
||||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_INPUT, NULL, "Input Device");
|
powerFSM.add_transition(&stateDARK, &stateON, EVENT_INPUT, NULL, "Input Device");
|
||||||
powerFSM.add_transition(&stateON, &stateON, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
|
powerFSM.add_transition(&stateON, &stateON, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
|
||||||
|
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_INPUT, NULL, "Input Device"); // restarts the sleep timer
|
||||||
|
|
||||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
||||||
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
|
||||||
@@ -299,10 +314,10 @@ void PowerFSM_setup()
|
|||||||
powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
|
powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
|
||||||
|
|
||||||
// Show the received text message
|
// Show the received text message
|
||||||
powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
|
powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
|
||||||
powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
|
powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
|
||||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
|
powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
|
||||||
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
|
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text"); // restarts the sleep timer
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are not in statePOWER but get a serial connection, suppress sleep (and keep the screen on) while connected
|
// If we are not in statePOWER but get a serial connection, suppress sleep (and keep the screen on) while connected
|
||||||
@@ -330,6 +345,12 @@ void PowerFSM_setup()
|
|||||||
powerFSM.add_timed_transition(&stateON, &stateDARK,
|
powerFSM.add_timed_transition(&stateON, &stateDARK,
|
||||||
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
||||||
"Screen-on timeout");
|
"Screen-on timeout");
|
||||||
|
powerFSM.add_timed_transition(&statePOWER, &stateDARK,
|
||||||
|
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
||||||
|
"Screen-on timeout");
|
||||||
|
powerFSM.add_timed_transition(&stateDARK, &stateDARK,
|
||||||
|
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
|
||||||
|
"Screen-on timeout");
|
||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
State *lowPowerState = &stateLS;
|
State *lowPowerState = &stateLS;
|
||||||
@@ -350,5 +371,5 @@ void PowerFSM_setup()
|
|||||||
"mesh timeout");
|
"mesh timeout");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
|
powerFSM.run_machine(); // run one iteration of the state machine, so we run our on enter tasks for the initial DARK state
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
#define EVENT_WAKE_TIMER 2
|
#define EVENT_WAKE_TIMER 2
|
||||||
// #define EVENT_RECEIVED_PACKET 3
|
// #define EVENT_RECEIVED_PACKET 3
|
||||||
#define EVENT_PACKET_FOR_PHONE 4
|
#define EVENT_PACKET_FOR_PHONE 4
|
||||||
#define EVENT_RECEIVED_TEXT_MSG 5
|
#define EVENT_RECEIVED_MSG 5
|
||||||
// #define EVENT_BOOT 6 // now done with a timed transition
|
// #define EVENT_BOOT 6 // now done with a timed transition
|
||||||
#define EVENT_BLUETOOTH_PAIR 7
|
#define EVENT_BLUETOOTH_PAIR 7
|
||||||
#define EVENT_NODEDB_UPDATED 8 // NodeDB has a big enough change that we think you should turn on the screen
|
#define EVENT_NODEDB_UPDATED 8 // NodeDB has a big enough change that we think you should turn on the screen
|
||||||
@@ -23,6 +23,6 @@
|
|||||||
#define EVENT_INPUT 17 // input broker wants something, we need to wake up and enable screen
|
#define EVENT_INPUT 17 // input broker wants something, we need to wake up and enable screen
|
||||||
|
|
||||||
extern Fsm powerFSM;
|
extern Fsm powerFSM;
|
||||||
extern State statePOWER, stateSERIAL;
|
extern State stateON, statePOWER, stateSERIAL, stateDARK;
|
||||||
|
|
||||||
void PowerFSM_setup();
|
void PowerFSM_setup();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class PowerFSMThread : public OSThread
|
|||||||
|
|
||||||
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
|
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
|
||||||
/// cpu for serial rx - FIXME)
|
/// cpu for serial rx - FIXME)
|
||||||
auto state = powerFSM.getState();
|
const auto state = powerFSM.getState();
|
||||||
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
|
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
|
||||||
|
|
||||||
if (powerStatus->getHasUSB()) {
|
if (powerStatus->getHasUSB()) {
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
#ifdef USE_RF95
|
#ifdef USE_RF95
|
||||||
#define RF95_RESET LORA_RESET
|
#define RF95_RESET LORA_RESET
|
||||||
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
|
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
|
||||||
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95
|
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95, but used for pure SX127x
|
||||||
#define RF95_DIO2 LORA_DIO2 // Note: not really used for RF95
|
#define RF95_DIO2 LORA_DIO2 // Note: not really used for RF95
|
||||||
#endif
|
#endif
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@@ -13,6 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
NoopPrint noopPrint;
|
NoopPrint noopPrint;
|
||||||
|
|
||||||
|
#if HAS_WIFI || HAS_ETHERNET
|
||||||
|
extern Syslog syslog;
|
||||||
|
#endif
|
||||||
|
|
||||||
void RedirectablePrint::setDestination(Print *_dest)
|
void RedirectablePrint::setDestination(Print *_dest)
|
||||||
{
|
{
|
||||||
assert(_dest);
|
assert(_dest);
|
||||||
@@ -56,6 +62,9 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
|||||||
|
|
||||||
size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||||
{
|
{
|
||||||
|
if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, "DEBUG") == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
size_t r = 0;
|
size_t r = 0;
|
||||||
|
|
||||||
if (!inDebugPrint) {
|
if (!inDebugPrint) {
|
||||||
@@ -96,6 +105,39 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
r += vprintf(format, arg);
|
r += vprintf(format, arg);
|
||||||
|
|
||||||
|
#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO)
|
||||||
|
// if syslog is in use, collect the log messages and send them to syslog
|
||||||
|
if (syslog.isEnabled()) {
|
||||||
|
int ll = 0;
|
||||||
|
switch (logLevel[0]) {
|
||||||
|
case 'D':
|
||||||
|
ll = SYSLOG_DEBUG;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
ll = SYSLOG_INFO;
|
||||||
|
break;
|
||||||
|
case 'W':
|
||||||
|
ll = SYSLOG_WARN;
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
ll = SYSLOG_ERR;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
ll = SYSLOG_CRIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ll = 0;
|
||||||
|
}
|
||||||
|
auto thread = concurrency::OSThread::currentThread;
|
||||||
|
if (thread) {
|
||||||
|
syslog.vlogf(ll, thread->ThreadName.c_str(), format, arg);
|
||||||
|
} else {
|
||||||
|
syslog.vlogf(ll, format, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
|
|
||||||
isContinuationMessage = !hasNewline;
|
isContinuationMessage = !hasNewline;
|
||||||
@@ -136,3 +178,22 @@ void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16
|
|||||||
}
|
}
|
||||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RedirectablePrint::mt_sprintf(const std::string fmt_str, ...)
|
||||||
|
{
|
||||||
|
int n = ((int)fmt_str.size()) * 2; /* Reserve two times as much as the length of the fmt_str */
|
||||||
|
std::unique_ptr<char[]> formatted;
|
||||||
|
va_list ap;
|
||||||
|
while (1) {
|
||||||
|
formatted.reset(new char[n]); /* Wrap the plain char array into the unique_ptr */
|
||||||
|
strcpy(&formatted[0], fmt_str.c_str());
|
||||||
|
va_start(ap, fmt_str);
|
||||||
|
int final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
|
||||||
|
va_end(ap);
|
||||||
|
if (final_n < 0 || final_n >= n)
|
||||||
|
n += abs(final_n - n + 1);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return std::string(formatted.get());
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <Print.h>
|
#include <Print.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Printable that can be switched to squirt its bytes to a different sink.
|
* A Printable that can be switched to squirt its bytes to a different sink.
|
||||||
@@ -40,6 +41,8 @@ class RedirectablePrint : public Print
|
|||||||
size_t vprintf(const char *format, va_list arg);
|
size_t vprintf(const char *format, va_list arg);
|
||||||
|
|
||||||
void hexDump(const char *logLevel, unsigned char *buf, uint16_t len);
|
void hexDump(const char *logLevel, unsigned char *buf, uint16_t len);
|
||||||
|
|
||||||
|
std::string mt_sprintf(const std::string fmt_str, ...);
|
||||||
};
|
};
|
||||||
|
|
||||||
class NoopPrint : public Print
|
class NoopPrint : public Print
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
|
|||||||
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
|
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
|
||||||
|
|
||||||
Port.begin(SERIAL_BAUD);
|
Port.begin(SERIAL_BAUD);
|
||||||
#if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
#if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(ARCH_RP2040)
|
||||||
time_t timeout = millis();
|
time_t timeout = millis();
|
||||||
while (!Port) {
|
while (!Port) {
|
||||||
if ((millis() - timeout) < 5000) {
|
if ((millis() - timeout) < 5000) {
|
||||||
|
|||||||
@@ -6,20 +6,22 @@ AirTime *airTime = NULL;
|
|||||||
|
|
||||||
// Don't read out of this directly. Use the helper functions.
|
// Don't read out of this directly. Use the helper functions.
|
||||||
|
|
||||||
|
uint32_t air_period_tx[PERIODS_TO_LOG];
|
||||||
|
uint32_t air_period_rx[PERIODS_TO_LOG];
|
||||||
|
|
||||||
void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
|
void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (reportType == TX_LOG) {
|
if (reportType == TX_LOG) {
|
||||||
LOG_DEBUG("AirTime - Packet transmitted : %ums\n", airtime_ms);
|
LOG_DEBUG("AirTime - Packet transmitted : %ums\n", airtime_ms);
|
||||||
this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms;
|
this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms;
|
||||||
myNodeInfo.air_period_tx[0] = myNodeInfo.air_period_tx[0] + airtime_ms;
|
air_period_tx[0] = air_period_tx[0] + airtime_ms;
|
||||||
|
|
||||||
this->utilizationTX[this->getPeriodUtilHour()] = this->utilizationTX[this->getPeriodUtilHour()] + airtime_ms;
|
this->utilizationTX[this->getPeriodUtilHour()] = this->utilizationTX[this->getPeriodUtilHour()] + airtime_ms;
|
||||||
|
|
||||||
} else if (reportType == RX_LOG) {
|
} else if (reportType == RX_LOG) {
|
||||||
LOG_DEBUG("AirTime - Packet received : %ums\n", airtime_ms);
|
LOG_DEBUG("AirTime - Packet received : %ums\n", airtime_ms);
|
||||||
this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms;
|
this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms;
|
||||||
myNodeInfo.air_period_rx[0] = myNodeInfo.air_period_rx[0] + airtime_ms;
|
air_period_rx[0] = air_period_rx[0] + airtime_ms;
|
||||||
} else if (reportType == RX_ALL_LOG) {
|
} else if (reportType == RX_ALL_LOG) {
|
||||||
LOG_DEBUG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
|
LOG_DEBUG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
|
||||||
this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms;
|
this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms;
|
||||||
@@ -55,16 +57,16 @@ void AirTime::airtimeRotatePeriod()
|
|||||||
this->airtimes.periodRX[i + 1] = this->airtimes.periodRX[i];
|
this->airtimes.periodRX[i + 1] = this->airtimes.periodRX[i];
|
||||||
this->airtimes.periodRX_ALL[i + 1] = this->airtimes.periodRX_ALL[i];
|
this->airtimes.periodRX_ALL[i + 1] = this->airtimes.periodRX_ALL[i];
|
||||||
|
|
||||||
myNodeInfo.air_period_tx[i + 1] = this->airtimes.periodTX[i];
|
air_period_tx[i + 1] = this->airtimes.periodTX[i];
|
||||||
myNodeInfo.air_period_rx[i + 1] = this->airtimes.periodRX[i];
|
air_period_rx[i + 1] = this->airtimes.periodRX[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
this->airtimes.periodTX[0] = 0;
|
this->airtimes.periodTX[0] = 0;
|
||||||
this->airtimes.periodRX[0] = 0;
|
this->airtimes.periodRX[0] = 0;
|
||||||
this->airtimes.periodRX_ALL[0] = 0;
|
this->airtimes.periodRX_ALL[0] = 0;
|
||||||
|
|
||||||
myNodeInfo.air_period_tx[0] = 0;
|
air_period_tx[0] = 0;
|
||||||
myNodeInfo.air_period_rx[0] = 0;
|
air_period_rx[0] = 0;
|
||||||
|
|
||||||
this->airtimes.lastPeriodIndex = this->currentPeriodIndex();
|
this->airtimes.lastPeriodIndex = this->currentPeriodIndex();
|
||||||
}
|
}
|
||||||
@@ -179,18 +181,17 @@ int32_t AirTime::runOnce()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init airtime windows to all 0
|
// Init airtime windows to all 0
|
||||||
for (int i = 0; i < myNodeInfo.air_period_rx_count; i++) {
|
for (int i = 0; i < PERIODS_TO_LOG; i++) {
|
||||||
this->airtimes.periodTX[i] = 0;
|
this->airtimes.periodTX[i] = 0;
|
||||||
this->airtimes.periodRX[i] = 0;
|
this->airtimes.periodRX[i] = 0;
|
||||||
this->airtimes.periodRX_ALL[i] = 0;
|
this->airtimes.periodRX_ALL[i] = 0;
|
||||||
|
|
||||||
// myNodeInfo.air_period_tx[i] = 0;
|
// air_period_tx[i] = 0;
|
||||||
// myNodeInfo.air_period_rx[i] = 0;
|
// air_period_rx[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
firstTime = false;
|
firstTime = false;
|
||||||
lastUtilPeriod = utilPeriod;
|
lastUtilPeriod = utilPeriod;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this->airtimeRotatePeriod();
|
this->airtimeRotatePeriod();
|
||||||
|
|
||||||
@@ -206,12 +207,6 @@ int32_t AirTime::runOnce()
|
|||||||
|
|
||||||
this->utilizationTX[utilPeriodTX] = 0;
|
this->utilizationTX[utilPeriodTX] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update channel_utilization every second.
|
|
||||||
myNodeInfo.channel_utilization = airTime->channelUtilizationPercent();
|
|
||||||
|
|
||||||
// Update channel_utilization every second.
|
|
||||||
myNodeInfo.air_util_tx = airTime->utilizationTXPercent();
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
LOG_DEBUG("utilPeriodTX %d TX Airtime %3.2f%\n", utilPeriodTX, airTime->utilizationTXPercent());
|
LOG_DEBUG("utilPeriodTX %d TX Airtime %3.2f%\n", utilPeriodTX, airTime->utilizationTXPercent());
|
||||||
@@ -223,4 +218,4 @@ int32_t AirTime::runOnce()
|
|||||||
LOG_DEBUG("\n");
|
LOG_DEBUG("\n");
|
||||||
*/
|
*/
|
||||||
return (1000 * 1);
|
return (1000 * 1);
|
||||||
}
|
}
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
|
|
||||||
Example analytics:
|
Example analytics:
|
||||||
|
|
||||||
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel.
|
TX_LOG + RX_LOG = Total air time for a particular meshtastic channel.
|
||||||
|
|
||||||
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including
|
TX_LOG + RX_LOG = Total air time for a particular meshtastic channel, including
|
||||||
other lora radios.
|
other lora radios.
|
||||||
|
|
||||||
RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.
|
RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.
|
||||||
|
|||||||
@@ -15,4 +15,6 @@ enum class Cmd {
|
|||||||
PRINT,
|
PRINT,
|
||||||
START_SHUTDOWN_SCREEN,
|
START_SHUTDOWN_SCREEN,
|
||||||
START_REBOOT_SCREEN,
|
START_REBOOT_SCREEN,
|
||||||
|
SHOW_PREV_FRAME,
|
||||||
|
SHOW_NEXT_FRAME
|
||||||
};
|
};
|
||||||
@@ -18,7 +18,7 @@ namespace concurrency
|
|||||||
*
|
*
|
||||||
* Useful for they top level loop() delay call to keep the CPU powered down until our next scheduled event or some external event.
|
* Useful for they top level loop() delay call to keep the CPU powered down until our next scheduled event or some external event.
|
||||||
*
|
*
|
||||||
* This is implmented for FreeRTOS but should be easy to port to other operating systems.
|
* This is implemented for FreeRTOS but should be easy to port to other operating systems.
|
||||||
*/
|
*/
|
||||||
class InterruptableDelay
|
class InterruptableDelay
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,12 +31,14 @@ IRAM_ATTR bool NotifiedWorkerThread::notifyCommon(uint32_t v, bool overwrite)
|
|||||||
runASAP = true;
|
runASAP = true;
|
||||||
|
|
||||||
notification = v;
|
notification = v;
|
||||||
if (debugNotification)
|
if (debugNotification) {
|
||||||
LOG_DEBUG("setting notification %d\n", v);
|
LOG_DEBUG("setting notification %d\n", v);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (debugNotification)
|
if (debugNotification) {
|
||||||
LOG_DEBUG("dropping notification %d\n", v);
|
LOG_DEBUG("dropping notification %d\n", v);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,8 +66,9 @@ bool NotifiedWorkerThread::notifyLater(uint32_t delay, uint32_t v, bool overwrit
|
|||||||
|
|
||||||
if (didIt) { // If we didn't already have something queued, override the delay to be larger
|
if (didIt) { // If we didn't already have something queued, override the delay to be larger
|
||||||
setIntervalFromNow(delay); // a new version of setInterval relative to the current time
|
setIntervalFromNow(delay); // a new version of setInterval relative to the current time
|
||||||
if (debugNotification)
|
if (debugNotification) {
|
||||||
LOG_DEBUG("delaying notification %u\n", delay);
|
LOG_DEBUG("delaying notification %u\n", delay);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return didIt;
|
return didIt;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "OSThread.h"
|
#include "OSThread.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "memGet.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
namespace concurrency
|
namespace concurrency
|
||||||
@@ -60,14 +61,17 @@ bool OSThread::shouldRun(unsigned long time)
|
|||||||
{
|
{
|
||||||
bool r = Thread::shouldRun(time);
|
bool r = Thread::shouldRun(time);
|
||||||
|
|
||||||
if (showRun && r)
|
if (showRun && r) {
|
||||||
LOG_DEBUG("Thread %s: run\n", ThreadName.c_str());
|
LOG_DEBUG("Thread %s: run\n", ThreadName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (showWaiting && enabled && !r)
|
if (showWaiting && enabled && !r) {
|
||||||
LOG_DEBUG("Thread %s: wait %lu\n", ThreadName.c_str(), interval);
|
LOG_DEBUG("Thread %s: wait %lu\n", ThreadName.c_str(), interval);
|
||||||
|
}
|
||||||
|
|
||||||
if (showDisabled && !enabled)
|
if (showDisabled && !enabled) {
|
||||||
LOG_DEBUG("Thread %s: disabled\n", ThreadName.c_str());
|
LOG_DEBUG("Thread %s: disabled\n", ThreadName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -75,12 +79,12 @@ bool OSThread::shouldRun(unsigned long time)
|
|||||||
void OSThread::run()
|
void OSThread::run()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_HEAP
|
#ifdef DEBUG_HEAP
|
||||||
auto heap = ESP.getFreeHeap();
|
auto heap = memGet.getFreeHeap();
|
||||||
#endif
|
#endif
|
||||||
currentThread = this;
|
currentThread = this;
|
||||||
auto newDelay = runOnce();
|
auto newDelay = runOnce();
|
||||||
#ifdef DEBUG_HEAP
|
#ifdef DEBUG_HEAP
|
||||||
auto newHeap = ESP.getFreeHeap();
|
auto newHeap = memGet.getFreeHeap();
|
||||||
if (newHeap < heap)
|
if (newHeap < heap)
|
||||||
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------\n", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------\n", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||||
if (heap < newHeap)
|
if (heap < newHeap)
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
// #define DISABLE_NTP
|
// #define DISABLE_NTP
|
||||||
|
|
||||||
// Disable the welcome screen and allow
|
// Disable the welcome screen and allow
|
||||||
//#define DISABLE_WELCOME_UNSET
|
// #define DISABLE_WELCOME_UNSET
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// OLED & Input
|
// OLED & Input
|
||||||
@@ -93,13 +93,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
// The SH1106 controller is almost, but not quite, the same as SSD1306
|
// The SH1106 controller is almost, but not quite, the same as SSD1306
|
||||||
// Define this if you know you have that controller or your "SSD1306" misbehaves.
|
// Define this if you know you have that controller or your "SSD1306" misbehaves.
|
||||||
//#define USE_SH1106
|
// #define USE_SH1106
|
||||||
|
|
||||||
// Define if screen should be mirrored left to right
|
// Define if screen should be mirrored left to right
|
||||||
// #define SCREEN_MIRROR
|
// #define SCREEN_MIRROR
|
||||||
|
|
||||||
// The m5stack I2C Keyboard (also RAK14004)
|
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
|
||||||
#define CARDKB_ADDR 0x5F
|
#define CARDKB_ADDR 0x5F
|
||||||
|
#define TDECK_KB_ADDR 0x55
|
||||||
|
#define BBQ10_KB_ADDR 0x1F
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// SENSOR
|
// SENSOR
|
||||||
@@ -116,6 +118,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define LPS22HB_ADDR 0x5C
|
#define LPS22HB_ADDR 0x5C
|
||||||
#define LPS22HB_ADDR_ALT 0x5D
|
#define LPS22HB_ADDR_ALT 0x5D
|
||||||
#define SHT31_ADDR 0x44
|
#define SHT31_ADDR 0x44
|
||||||
|
#define PMSA0031_ADDR 0x12
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// ACCELEROMETER
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
#define MPU6050_ADDR 0x68
|
||||||
|
#define LIS3DH_ADR 0x18
|
||||||
|
#define BMA423_ADDR 0x19
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// LED
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
#define NCP5623_ADDR 0x38
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Security
|
// Security
|
||||||
@@ -133,6 +148,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define GPS_THREAD_INTERVAL 100
|
#define GPS_THREAD_INTERVAL 100
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// convert 24-bit color to 16-bit (56K)
|
||||||
|
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
|
||||||
|
|
||||||
/* Step #1: offer chance for variant-specific defines */
|
/* Step #1: offer chance for variant-specific defines */
|
||||||
#include "variant.h"
|
#include "variant.h"
|
||||||
|
|
||||||
@@ -160,6 +178,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#ifndef HAS_BUTTON
|
#ifndef HAS_BUTTON
|
||||||
#define HAS_BUTTON 0
|
#define HAS_BUTTON 0
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef HAS_TRACKBALL
|
||||||
|
#define HAS_TRACKBALL 0
|
||||||
|
#endif
|
||||||
|
#ifndef HAS_TOUCHSCREEN
|
||||||
|
#define HAS_TOUCHSCREEN 0
|
||||||
|
#endif
|
||||||
#ifndef HAS_TELEMETRY
|
#ifndef HAS_TELEMETRY
|
||||||
#define HAS_TELEMETRY 0
|
#define HAS_TELEMETRY 0
|
||||||
#endif
|
#endif
|
||||||
@@ -181,4 +205,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#ifndef HW_VENDOR
|
#ifndef HW_VENDOR
|
||||||
#error HW_VENDOR must be defined
|
#error HW_VENDOR must be defined
|
||||||
#endif
|
#endif
|
||||||
76
src/detect/ScanI2C.cpp
Normal file
76
src/detect/ScanI2C.cpp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#include "ScanI2C.h"
|
||||||
|
|
||||||
|
const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress();
|
||||||
|
const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE);
|
||||||
|
|
||||||
|
ScanI2C::ScanI2C() = default;
|
||||||
|
|
||||||
|
void ScanI2C::scanPort(ScanI2C::I2CPort port) {}
|
||||||
|
|
||||||
|
void ScanI2C::setSuppressScreen()
|
||||||
|
{
|
||||||
|
shouldSuppressScreen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice ScanI2C::firstScreen() const
|
||||||
|
{
|
||||||
|
// Allow to override the scanner results for screen
|
||||||
|
if (shouldSuppressScreen)
|
||||||
|
return DEVICE_NONE;
|
||||||
|
|
||||||
|
ScanI2C::DeviceType types[] = {SCREEN_SSD1306, SCREEN_SH1106, SCREEN_ST7567, SCREEN_UNKNOWN};
|
||||||
|
return firstOfOrNONE(4, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice ScanI2C::firstRTC() const
|
||||||
|
{
|
||||||
|
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563};
|
||||||
|
return firstOfOrNONE(2, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
||||||
|
{
|
||||||
|
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004};
|
||||||
|
return firstOfOrNONE(4, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
|
||||||
|
{
|
||||||
|
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423};
|
||||||
|
return firstOfOrNONE(3, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const
|
||||||
|
{
|
||||||
|
return DEVICE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScanI2C::exists(ScanI2C::DeviceType) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice ScanI2C::firstOfOrNONE(size_t count, ScanI2C::DeviceType *types) const
|
||||||
|
{
|
||||||
|
return DEVICE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ScanI2C::countDevices() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::DeviceAddress::DeviceAddress(ScanI2C::I2CPort port, uint8_t address) : port(port), address(address) {}
|
||||||
|
|
||||||
|
ScanI2C::DeviceAddress::DeviceAddress() : DeviceAddress(I2CPort::NO_I2C, 0) {}
|
||||||
|
|
||||||
|
bool ScanI2C::DeviceAddress::operator<(const ScanI2C::DeviceAddress &other) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
// If this one has no port and other has a port
|
||||||
|
(port == NO_I2C && other.port != NO_I2C)
|
||||||
|
// if both have a port and this one's address is lower
|
||||||
|
|| (port != NO_I2C && other.port != NO_I2C && (address < other.address));
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {}
|
||||||
103
src/detect/ScanI2C.h
Normal file
103
src/detect/ScanI2C.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class ScanI2C
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef enum DeviceType {
|
||||||
|
NONE,
|
||||||
|
SCREEN_SSD1306,
|
||||||
|
SCREEN_SH1106,
|
||||||
|
SCREEN_UNKNOWN, // has the same address as the two above but does not respond to the same commands
|
||||||
|
SCREEN_ST7567,
|
||||||
|
ATECC608B,
|
||||||
|
RTC_RV3028,
|
||||||
|
RTC_PCF8563,
|
||||||
|
CARDKB,
|
||||||
|
TDECKKB,
|
||||||
|
BBQ10KB,
|
||||||
|
RAK14004,
|
||||||
|
PMU_AXP192_AXP2101,
|
||||||
|
BME_680,
|
||||||
|
BME_280,
|
||||||
|
BMP_280,
|
||||||
|
INA260,
|
||||||
|
INA219,
|
||||||
|
MCP9808,
|
||||||
|
SHT31,
|
||||||
|
SHTC3,
|
||||||
|
LPS22HB,
|
||||||
|
QMC6310,
|
||||||
|
QMI8658,
|
||||||
|
QMC5883L,
|
||||||
|
PMSA0031,
|
||||||
|
MPU6050,
|
||||||
|
LIS3DH,
|
||||||
|
BMA423,
|
||||||
|
#ifdef HAS_NCP5623
|
||||||
|
NCP5623,
|
||||||
|
#endif
|
||||||
|
} DeviceType;
|
||||||
|
|
||||||
|
// typedef uint8_t DeviceAddress;
|
||||||
|
typedef enum I2CPort {
|
||||||
|
NO_I2C,
|
||||||
|
WIRE,
|
||||||
|
WIRE1,
|
||||||
|
} I2CPort;
|
||||||
|
|
||||||
|
typedef struct DeviceAddress {
|
||||||
|
I2CPort port;
|
||||||
|
uint8_t address;
|
||||||
|
|
||||||
|
explicit DeviceAddress(I2CPort port, uint8_t address);
|
||||||
|
DeviceAddress();
|
||||||
|
|
||||||
|
bool operator<(const DeviceAddress &other) const;
|
||||||
|
} DeviceAddress;
|
||||||
|
|
||||||
|
static const DeviceAddress ADDRESS_NONE;
|
||||||
|
|
||||||
|
typedef uint8_t RegisterAddress;
|
||||||
|
|
||||||
|
typedef struct FoundDevice {
|
||||||
|
DeviceType type;
|
||||||
|
DeviceAddress address;
|
||||||
|
|
||||||
|
explicit FoundDevice(DeviceType = DeviceType::NONE, DeviceAddress = ADDRESS_NONE);
|
||||||
|
} FoundDevice;
|
||||||
|
|
||||||
|
static const FoundDevice DEVICE_NONE;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScanI2C();
|
||||||
|
|
||||||
|
virtual void scanPort(ScanI2C::I2CPort);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it.
|
||||||
|
*/
|
||||||
|
void setSuppressScreen();
|
||||||
|
|
||||||
|
FoundDevice firstScreen() const;
|
||||||
|
|
||||||
|
FoundDevice firstRTC() const;
|
||||||
|
|
||||||
|
FoundDevice firstKeyboard() const;
|
||||||
|
|
||||||
|
FoundDevice firstAccelerometer() const;
|
||||||
|
|
||||||
|
virtual FoundDevice find(DeviceType) const;
|
||||||
|
|
||||||
|
virtual bool exists(DeviceType) const;
|
||||||
|
|
||||||
|
virtual size_t countDevices() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual FoundDevice firstOfOrNONE(size_t, DeviceType[]) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool shouldSuppressScreen = false;
|
||||||
|
};
|
||||||
312
src/detect/ScanI2CTwoWire.cpp
Normal file
312
src/detect/ScanI2CTwoWire.cpp
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
#include "ScanI2CTwoWire.h"
|
||||||
|
|
||||||
|
#include "concurrency/LockGuard.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||||
|
#include "main.h" // atecc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp
|
||||||
|
#ifndef XPOWERS_AXP192_AXP2101_ADDRESS
|
||||||
|
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const
|
||||||
|
{
|
||||||
|
concurrency::LockGuard guard((concurrency::Lock *)&lock);
|
||||||
|
|
||||||
|
return exists(type) ? ScanI2C::FoundDevice(type, deviceAddresses.at(type)) : DEVICE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScanI2CTwoWire::exists(ScanI2C::DeviceType type) const
|
||||||
|
{
|
||||||
|
return deviceAddresses.find(type) != deviceAddresses.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice ScanI2CTwoWire::firstOfOrNONE(size_t count, DeviceType types[]) const
|
||||||
|
{
|
||||||
|
concurrency::LockGuard guard((concurrency::Lock *)&lock);
|
||||||
|
|
||||||
|
for (size_t k = 0; k < count; k++) {
|
||||||
|
ScanI2C::DeviceType current = types[k];
|
||||||
|
|
||||||
|
if (exists(current)) {
|
||||||
|
return ScanI2C::FoundDevice(current, deviceAddresses.at(current));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEVICE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const
|
||||||
|
{
|
||||||
|
TwoWire *i2cBus = fetchI2CBus(addr);
|
||||||
|
|
||||||
|
uint8_t r = 0;
|
||||||
|
uint8_t r_prev = 0;
|
||||||
|
uint8_t c = 0;
|
||||||
|
ScanI2C::DeviceType o_probe = ScanI2C::DeviceType::SCREEN_UNKNOWN;
|
||||||
|
do {
|
||||||
|
r_prev = r;
|
||||||
|
i2cBus->beginTransmission(addr.address);
|
||||||
|
i2cBus->write((uint8_t)0x00);
|
||||||
|
i2cBus->endTransmission();
|
||||||
|
i2cBus->requestFrom((int)addr.address, 1);
|
||||||
|
if (i2cBus->available()) {
|
||||||
|
r = i2cBus->read();
|
||||||
|
}
|
||||||
|
r &= 0x0f;
|
||||||
|
|
||||||
|
if (r == 0x08 || r == 0x00) {
|
||||||
|
LOG_INFO("sh1106 display found\n");
|
||||||
|
o_probe = SCREEN_SH1106; // SH1106
|
||||||
|
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
|
||||||
|
LOG_INFO("ssd1306 display found\n");
|
||||||
|
o_probe = SCREEN_SSD1306; // SSD1306
|
||||||
|
}
|
||||||
|
c++;
|
||||||
|
} while ((r != r_prev) && (c < 4));
|
||||||
|
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
|
||||||
|
|
||||||
|
return o_probe;
|
||||||
|
}
|
||||||
|
void ScanI2CTwoWire::printATECCInfo() const
|
||||||
|
{
|
||||||
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||||
|
atecc.readConfigZone(false);
|
||||||
|
|
||||||
|
LOG_DEBUG("ATECC608B Serial Number: ");
|
||||||
|
for (int i = 0; i < 9; i++) {
|
||||||
|
LOG_DEBUG("%02x", atecc.serialNumber[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(", Rev Number: ");
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
LOG_DEBUG("%02x", atecc.revisionNumber[i]);
|
||||||
|
}
|
||||||
|
LOG_DEBUG("\n");
|
||||||
|
|
||||||
|
LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked");
|
||||||
|
LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
|
||||||
|
LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked");
|
||||||
|
|
||||||
|
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
|
||||||
|
if (atecc.generatePublicKey() == false) {
|
||||||
|
LOG_DEBUG("ATECC608B Error generating public key\n");
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("ATECC608B Public Key: ");
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]);
|
||||||
|
}
|
||||||
|
LOG_DEBUG("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation ®isterLocation,
|
||||||
|
ScanI2CTwoWire::ResponseWidth responseWidth) const
|
||||||
|
{
|
||||||
|
uint16_t value = 0x00;
|
||||||
|
TwoWire *i2cBus = fetchI2CBus(registerLocation.i2cAddress);
|
||||||
|
|
||||||
|
i2cBus->beginTransmission(registerLocation.i2cAddress.address);
|
||||||
|
i2cBus->write(registerLocation.registerAddress);
|
||||||
|
i2cBus->endTransmission();
|
||||||
|
delay(20);
|
||||||
|
i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth);
|
||||||
|
LOG_DEBUG("Wire.available() = %d\n", i2cBus->available());
|
||||||
|
if (i2cBus->available() == 2) {
|
||||||
|
// Read MSB, then LSB
|
||||||
|
value = (uint16_t)i2cBus->read() << 8;
|
||||||
|
value |= i2cBus->read();
|
||||||
|
} else if (i2cBus->available()) {
|
||||||
|
value = i2cBus->read();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
|
||||||
|
case ADDR: \
|
||||||
|
LOG_INFO(__VA_ARGS__); \
|
||||||
|
type = T; \
|
||||||
|
break;
|
||||||
|
|
||||||
|
void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||||
|
{
|
||||||
|
concurrency::LockGuard guard((concurrency::Lock *)&lock);
|
||||||
|
|
||||||
|
LOG_DEBUG("Scanning for i2c devices on port %d\n", port);
|
||||||
|
|
||||||
|
uint8_t err;
|
||||||
|
|
||||||
|
DeviceAddress addr(port, 0x00);
|
||||||
|
|
||||||
|
uint16_t registerValue = 0x00;
|
||||||
|
ScanI2C::DeviceType type;
|
||||||
|
TwoWire *i2cBus;
|
||||||
|
#ifdef RV3028_RTC
|
||||||
|
Melopero_RV3028 rtc;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef I2C_SDA1
|
||||||
|
if (port == I2CPort::WIRE1) {
|
||||||
|
i2cBus = &Wire1;
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
i2cBus = &Wire;
|
||||||
|
#ifdef I2C_SDA1
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (addr.address = 1; addr.address < 127; addr.address++) {
|
||||||
|
i2cBus->beginTransmission(addr.address);
|
||||||
|
err = i2cBus->endTransmission();
|
||||||
|
type = NONE;
|
||||||
|
if (err == 0) {
|
||||||
|
LOG_DEBUG("I2C device found at address 0x%x\n", addr.address);
|
||||||
|
|
||||||
|
switch (addr.address) {
|
||||||
|
case SSD1306_ADDRESS:
|
||||||
|
type = probeOLED(addr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||||
|
case ATECC608B_ADDR:
|
||||||
|
type = ATECC608B;
|
||||||
|
if (atecc.begin(addr.address) == true) {
|
||||||
|
LOG_INFO("ATECC608B initialized\n");
|
||||||
|
} else {
|
||||||
|
LOG_WARN("ATECC608B initialization failed\n");
|
||||||
|
}
|
||||||
|
printATECCInfo();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RV3028_RTC
|
||||||
|
case RV3028_RTC:
|
||||||
|
// foundDevices[addr] = RTC_RV3028;
|
||||||
|
type = RTC_RV3028;
|
||||||
|
LOG_INFO("RV3028 RTC found\n");
|
||||||
|
rtc.initI2C(*i2cBus);
|
||||||
|
rtc.writeToRegister(0x35, 0x07); // no Clkout
|
||||||
|
rtc.writeToRegister(0x37, 0xB4);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PCF8563_RTC
|
||||||
|
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563 RTC found\n")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case CARDKB_ADDR:
|
||||||
|
// Do we have the RAK14006 instead?
|
||||||
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1);
|
||||||
|
if (registerValue == 0x02) {
|
||||||
|
// KEYPAD_VERSION
|
||||||
|
LOG_INFO("RAK14004 found\n");
|
||||||
|
type = RAK14004;
|
||||||
|
} else {
|
||||||
|
LOG_INFO("m5 cardKB found\n");
|
||||||
|
type = CARDKB;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
|
||||||
|
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found\n");
|
||||||
|
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
|
||||||
|
#ifdef HAS_NCP5623
|
||||||
|
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
|
||||||
|
#endif
|
||||||
|
#ifdef HAS_PMU
|
||||||
|
SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found\n")
|
||||||
|
#endif
|
||||||
|
case BME_ADDR:
|
||||||
|
case BME_ADDR_ALTERNATE:
|
||||||
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID
|
||||||
|
switch (registerValue) {
|
||||||
|
case 0x61:
|
||||||
|
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||||
|
type = BME_680;
|
||||||
|
break;
|
||||||
|
case 0x60:
|
||||||
|
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||||
|
type = BME_280;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||||
|
type = BMP_280;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INA_ADDR:
|
||||||
|
case INA_ADDR_ALTERNATE:
|
||||||
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
|
||||||
|
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
|
||||||
|
if (registerValue == 0x5449) {
|
||||||
|
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||||
|
type = INA260;
|
||||||
|
} else { // Assume INA219 if INA260 ID is not found
|
||||||
|
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||||
|
type = INA219;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MCP9808_ADDR:
|
||||||
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
|
||||||
|
if (registerValue == 0x0400) {
|
||||||
|
type = MCP9808;
|
||||||
|
LOG_INFO("MCP9808 sensor found\n");
|
||||||
|
} else {
|
||||||
|
type = LIS3DH;
|
||||||
|
LOG_INFO("LIS3DH accelerometer found\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
SCAN_SIMPLE_CASE(SHT31_ADDR, SHT31, "SHT31 sensor found\n")
|
||||||
|
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found\n")
|
||||||
|
|
||||||
|
case LPS22HB_ADDR_ALT:
|
||||||
|
SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB sensor found\n")
|
||||||
|
|
||||||
|
SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310 Highrate 3-Axis magnetic sensor found\n")
|
||||||
|
SCAN_SIMPLE_CASE(QMI8658_ADDR, QMI8658, "QMI8658 Highrate 6-Axis inertial measurement sensor found\n")
|
||||||
|
SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found\n")
|
||||||
|
|
||||||
|
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n")
|
||||||
|
SCAN_SIMPLE_CASE(MPU6050_ADDR, MPU6050, "MPU6050 accelerometer found\n");
|
||||||
|
SCAN_SIMPLE_CASE(BMA423_ADDR, BMA423, "BMA423 accelerometer found\n");
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
|
||||||
|
}
|
||||||
|
} else if (err == 4) {
|
||||||
|
LOG_ERROR("Unknown error at address 0x%x\n", addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a type was found for the enumerated device - save, if so
|
||||||
|
if (type != NONE) {
|
||||||
|
deviceAddresses[type] = addr;
|
||||||
|
foundDevices[addr] = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
|
||||||
|
{
|
||||||
|
if (address.port == ScanI2C::I2CPort::WIRE) {
|
||||||
|
return &Wire;
|
||||||
|
} else {
|
||||||
|
#ifdef I2C_SDA1
|
||||||
|
return &Wire1;
|
||||||
|
#else
|
||||||
|
return &Wire;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ScanI2CTwoWire::countDevices() const
|
||||||
|
{
|
||||||
|
return foundDevices.size();
|
||||||
|
}
|
||||||
56
src/detect/ScanI2CTwoWire.h
Normal file
56
src/detect/ScanI2CTwoWire.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
#include "ScanI2C.h"
|
||||||
|
|
||||||
|
#include "../concurrency/Lock.h"
|
||||||
|
|
||||||
|
class ScanI2CTwoWire : public ScanI2C
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void scanPort(ScanI2C::I2CPort) override;
|
||||||
|
|
||||||
|
ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override;
|
||||||
|
|
||||||
|
bool exists(ScanI2C::DeviceType) const override;
|
||||||
|
|
||||||
|
size_t countDevices() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FoundDevice firstOfOrNONE(size_t, DeviceType[]) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef struct RegisterLocation {
|
||||||
|
DeviceAddress i2cAddress;
|
||||||
|
RegisterAddress registerAddress;
|
||||||
|
|
||||||
|
RegisterLocation(DeviceAddress deviceAddress, RegisterAddress registerAddress)
|
||||||
|
: i2cAddress(deviceAddress), registerAddress(registerAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} RegisterLocation;
|
||||||
|
|
||||||
|
typedef uint8_t ResponseWidth;
|
||||||
|
|
||||||
|
std::map<ScanI2C::DeviceAddress, ScanI2C::DeviceType> foundDevices;
|
||||||
|
|
||||||
|
// note: prone to overwriting if multiple devices of a type are added at different addresses (rare?)
|
||||||
|
std::map<ScanI2C::DeviceType, ScanI2C::DeviceAddress> deviceAddresses;
|
||||||
|
|
||||||
|
concurrency::Lock lock;
|
||||||
|
|
||||||
|
void printATECCInfo() const;
|
||||||
|
|
||||||
|
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const;
|
||||||
|
|
||||||
|
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
|
||||||
|
|
||||||
|
TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "../configuration.h"
|
#include "../configuration.h"
|
||||||
|
|
||||||
#ifdef RAK4630
|
#ifdef RAK_4631
|
||||||
#include "../main.h"
|
#include "../main.h"
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
|
||||||
@@ -64,4 +64,4 @@ void scanEInkDevice(void)
|
|||||||
LOG_DEBUG("EInk display not found\n");
|
LOG_DEBUG("EInk display not found\n");
|
||||||
SPI1.end();
|
SPI1.end();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
#include "../configuration.h"
|
|
||||||
#include "../main.h"
|
|
||||||
#include "mesh/generated/meshtastic/telemetry.pb.h"
|
|
||||||
#include <Wire.h>
|
|
||||||
|
|
||||||
// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp
|
|
||||||
#ifndef XPOWERS_AXP192_AXP2101_ADDRESS
|
|
||||||
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if HAS_WIRE
|
|
||||||
|
|
||||||
void printATECCInfo()
|
|
||||||
{
|
|
||||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
|
||||||
atecc.readConfigZone(false);
|
|
||||||
|
|
||||||
LOG_DEBUG("ATECC608B Serial Number: ");
|
|
||||||
for (int i = 0; i < 9; i++) {
|
|
||||||
LOG_DEBUG("%02x", atecc.serialNumber[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG(", Rev Number: ");
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
LOG_DEBUG("%02x", atecc.revisionNumber[i]);
|
|
||||||
}
|
|
||||||
LOG_DEBUG("\n");
|
|
||||||
|
|
||||||
LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked");
|
|
||||||
LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
|
|
||||||
LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked");
|
|
||||||
|
|
||||||
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
|
|
||||||
if (atecc.generatePublicKey() == false) {
|
|
||||||
LOG_DEBUG("ATECC608B Error generating public key\n");
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG("ATECC608B Public Key: ");
|
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]);
|
|
||||||
}
|
|
||||||
LOG_DEBUG("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length)
|
|
||||||
{
|
|
||||||
uint16_t value = 0x00;
|
|
||||||
Wire.beginTransmission(address);
|
|
||||||
Wire.write(reg);
|
|
||||||
Wire.endTransmission();
|
|
||||||
delay(20);
|
|
||||||
Wire.requestFrom(address, length);
|
|
||||||
LOG_DEBUG("Wire.available() = %d\n", Wire.available());
|
|
||||||
if (Wire.available() == 2) {
|
|
||||||
// Read MSB, then LSB
|
|
||||||
value = (uint16_t)Wire.read() << 8;
|
|
||||||
value |= Wire.read();
|
|
||||||
} else if (Wire.available()) {
|
|
||||||
value = Wire.read();
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t oled_probe(byte addr)
|
|
||||||
{
|
|
||||||
uint8_t r = 0;
|
|
||||||
uint8_t r_prev = 0;
|
|
||||||
uint8_t c = 0;
|
|
||||||
uint8_t o_probe = 0;
|
|
||||||
do {
|
|
||||||
r_prev = r;
|
|
||||||
Wire.beginTransmission(addr);
|
|
||||||
Wire.write(0x00);
|
|
||||||
Wire.endTransmission();
|
|
||||||
Wire.requestFrom((int)addr, 1);
|
|
||||||
if (Wire.available()) {
|
|
||||||
r = Wire.read();
|
|
||||||
}
|
|
||||||
r &= 0x0f;
|
|
||||||
|
|
||||||
if (r == 0x08 || r == 0x00) {
|
|
||||||
o_probe = 2; // SH1106
|
|
||||||
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
|
|
||||||
o_probe = 1; // SSD1306
|
|
||||||
}
|
|
||||||
c++;
|
|
||||||
} while ((r != r_prev) && (c < 4));
|
|
||||||
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
|
|
||||||
return o_probe;
|
|
||||||
}
|
|
||||||
|
|
||||||
void scanI2Cdevice()
|
|
||||||
{
|
|
||||||
byte err, addr;
|
|
||||||
uint16_t registerValue = 0x00;
|
|
||||||
int nDevices = 0;
|
|
||||||
for (addr = 1; addr < 127; addr++) {
|
|
||||||
Wire.beginTransmission(addr);
|
|
||||||
err = Wire.endTransmission();
|
|
||||||
if (err == 0) {
|
|
||||||
LOG_DEBUG("I2C device found at address 0x%x\n", addr);
|
|
||||||
|
|
||||||
nDevices++;
|
|
||||||
|
|
||||||
if (addr == SSD1306_ADDRESS) {
|
|
||||||
screen_found = addr;
|
|
||||||
screen_model = oled_probe(addr);
|
|
||||||
if (screen_model == 1) {
|
|
||||||
LOG_INFO("ssd1306 display found\n");
|
|
||||||
} else if (screen_model == 2) {
|
|
||||||
LOG_INFO("sh1106 display found\n");
|
|
||||||
} else {
|
|
||||||
LOG_INFO("unknown display found\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
|
||||||
if (addr == ATECC608B_ADDR) {
|
|
||||||
keystore_found = addr;
|
|
||||||
if (atecc.begin(keystore_found) == true) {
|
|
||||||
LOG_INFO("ATECC608B initialized\n");
|
|
||||||
} else {
|
|
||||||
LOG_WARN("ATECC608B initialization failed\n");
|
|
||||||
}
|
|
||||||
printATECCInfo();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef RV3028_RTC
|
|
||||||
if (addr == RV3028_RTC) {
|
|
||||||
rtc_found = addr;
|
|
||||||
LOG_INFO("RV3028 RTC found\n");
|
|
||||||
Melopero_RV3028 rtc;
|
|
||||||
rtc.initI2C();
|
|
||||||
rtc.writeToRegister(0x35, 0x07); // no Clkout
|
|
||||||
rtc.writeToRegister(0x37, 0xB4);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef PCF8563_RTC
|
|
||||||
if (addr == PCF8563_RTC) {
|
|
||||||
rtc_found = addr;
|
|
||||||
LOG_INFO("PCF8563 RTC found\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (addr == CARDKB_ADDR) {
|
|
||||||
cardkb_found = addr;
|
|
||||||
// Do we have the RAK14006 instead?
|
|
||||||
registerValue = getRegisterValue(addr, 0x04, 1);
|
|
||||||
if (registerValue == 0x02) { // KEYPAD_VERSION
|
|
||||||
LOG_INFO("RAK14004 found\n");
|
|
||||||
kb_model = 0x02;
|
|
||||||
} else {
|
|
||||||
LOG_INFO("m5 cardKB found\n");
|
|
||||||
kb_model = 0x00;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (addr == ST7567_ADDRESS) {
|
|
||||||
screen_found = addr;
|
|
||||||
LOG_INFO("st7567 display found\n");
|
|
||||||
}
|
|
||||||
#ifdef HAS_PMU
|
|
||||||
if (addr == XPOWERS_AXP192_AXP2101_ADDRESS) {
|
|
||||||
pmu_found = true;
|
|
||||||
LOG_INFO("axp192/axp2101 PMU found\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
|
|
||||||
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
|
|
||||||
if (registerValue == 0x61) {
|
|
||||||
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME680] = addr;
|
|
||||||
} else if (registerValue == 0x60) {
|
|
||||||
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME280] = addr;
|
|
||||||
} else {
|
|
||||||
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BMP280] = addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
|
|
||||||
registerValue = getRegisterValue(addr, 0xFE, 2);
|
|
||||||
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
|
|
||||||
if (registerValue == 0x5449) {
|
|
||||||
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] = addr;
|
|
||||||
} else { // Assume INA219 if INA260 ID is not found
|
|
||||||
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] = addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (addr == MCP9808_ADDR) {
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MCP9808] = addr;
|
|
||||||
LOG_INFO("MCP9808 sensor found\n");
|
|
||||||
}
|
|
||||||
if (addr == SHT31_ADDR) {
|
|
||||||
LOG_INFO("SHT31 sensor found\n");
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHT31] = addr;
|
|
||||||
}
|
|
||||||
if (addr == SHTC3_ADDR) {
|
|
||||||
LOG_INFO("SHTC3 sensor found\n");
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHTC3] = addr;
|
|
||||||
}
|
|
||||||
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
|
|
||||||
LOG_INFO("LPS22HB sensor found\n");
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_LPS22] = addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// High rate sensors, will be processed internally
|
|
||||||
if (addr == QMC6310_ADDR) {
|
|
||||||
LOG_INFO("QMC6310 Highrate 3-Axis magnetic sensor found\n");
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC6310] = addr;
|
|
||||||
}
|
|
||||||
if (addr == QMI8658_ADDR) {
|
|
||||||
LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMI8658] = addr;
|
|
||||||
}
|
|
||||||
if (addr == QMC5883L_ADDR) {
|
|
||||||
LOG_INFO("QMC5883L Highrate 3-Axis magnetic sensor found\n");
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC5883L] = addr;
|
|
||||||
}
|
|
||||||
} else if (err == 4) {
|
|
||||||
LOG_ERROR("Unknow error at address 0x%x\n", addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nDevices == 0)
|
|
||||||
LOG_INFO("No I2C devices found\n");
|
|
||||||
else
|
|
||||||
LOG_INFO("%i I2C devices found\n", nDevices);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void scanI2Cdevice() {}
|
|
||||||
#endif
|
|
||||||
@@ -9,4 +9,4 @@
|
|||||||
|
|
||||||
/// Record an error that should be reported via analytics
|
/// Record an error that should be reported via analytics
|
||||||
void recordCriticalError(meshtastic_CriticalErrorCode code = meshtastic_CriticalErrorCode_UNSPECIFIED, uint32_t address = 0,
|
void recordCriticalError(meshtastic_CriticalErrorCode code = meshtastic_CriticalErrorCode_UNSPECIFIED, uint32_t address = 0,
|
||||||
const char *filename = NULL);
|
const char *filename = NULL);
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ARDUINO_NRF52_ADAFRUIT)
|
#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_RP2040)
|
||||||
#define HAS_FREE_RTOS
|
#define HAS_FREE_RTOS
|
||||||
|
|
||||||
#include <FreeRTOS.h>
|
#include <FreeRTOS.h>
|
||||||
@@ -44,4 +44,4 @@ typedef uint32_t BaseType_t;
|
|||||||
|
|
||||||
enum eNotifyAction { eNoAction, eSetValueWithoutOverwrite, eSetValueWithOverwrite };
|
enum eNotifyAction { eNoAction, eSetValueWithoutOverwrite, eSetValueWithOverwrite };
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
486
src/gps/GPS.cpp
486
src/gps/GPS.cpp
@@ -4,6 +4,10 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
|
|
||||||
|
#ifndef GPS_RESET_MODE
|
||||||
|
#define GPS_RESET_MODE HIGH
|
||||||
|
#endif
|
||||||
|
|
||||||
// If we have a serial GPS port it will not be null
|
// If we have a serial GPS port it will not be null
|
||||||
#ifdef GPS_SERIAL_NUM
|
#ifdef GPS_SERIAL_NUM
|
||||||
HardwareSerial _serial_gps_real(GPS_SERIAL_NUM);
|
HardwareSerial _serial_gps_real(GPS_SERIAL_NUM);
|
||||||
@@ -21,11 +25,29 @@ GPS *gps;
|
|||||||
/// only init that port once.
|
/// only init that port once.
|
||||||
static bool didSerialInit;
|
static bool didSerialInit;
|
||||||
|
|
||||||
bool GPS::getACK(uint8_t c, uint8_t i)
|
struct uBloxGnssModelInfo info;
|
||||||
|
uint8_t uBloxProtocolVersion;
|
||||||
|
|
||||||
|
void GPS::UBXChecksum(byte *message, size_t length)
|
||||||
|
{
|
||||||
|
uint8_t CK_A = 0, CK_B = 0;
|
||||||
|
|
||||||
|
// Calculate the checksum, starting from the CLASS field (which is message[2])
|
||||||
|
for (size_t i = 2; i < length - 2; i++) {
|
||||||
|
CK_A = (CK_A + message[i]) & 0xFF;
|
||||||
|
CK_B = (CK_B + CK_A) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place the calculated checksum values in the message
|
||||||
|
message[length - 2] = CK_A;
|
||||||
|
message[length - 1] = CK_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GPS::getACK(uint8_t class_id, uint8_t msg_id)
|
||||||
{
|
{
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
uint8_t ack = 0;
|
uint8_t ack = 0;
|
||||||
const uint8_t ackP[2] = {c, i};
|
const uint8_t ackP[2] = {class_id, msg_id};
|
||||||
uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
unsigned long startTime = millis();
|
unsigned long startTime = millis();
|
||||||
|
|
||||||
@@ -42,17 +64,23 @@ bool GPS::getACK(uint8_t c, uint8_t i)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (ack > 9) {
|
if (ack > 9) {
|
||||||
return true;
|
// LOG_INFO("Got ACK for class %02X message %02X\n", class_id, msg_id);
|
||||||
|
return true; // ACK received
|
||||||
}
|
}
|
||||||
if (millis() - startTime > 1000) {
|
if (millis() - startTime > 3000) {
|
||||||
return false;
|
LOG_WARN("No response for class %02X message %02X\n", class_id, msg_id);
|
||||||
|
return false; // No response received within 3 seconds
|
||||||
}
|
}
|
||||||
if (_serial_gps->available()) {
|
if (_serial_gps->available()) {
|
||||||
b = _serial_gps->read();
|
b = _serial_gps->read();
|
||||||
if (b == buf[ack]) {
|
if (b == buf[ack]) {
|
||||||
ack++;
|
ack++;
|
||||||
} else {
|
} else {
|
||||||
ack = 0;
|
ack = 0; // Reset the acknowledgement counter
|
||||||
|
if (buf[3] == 0x00) { // UBX-ACK-NAK message
|
||||||
|
LOG_WARN("Got NAK for class %02X message %02X\n", class_id, msg_id);
|
||||||
|
return false; // NAK received
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +101,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
|
|||||||
uint32_t startTime = millis();
|
uint32_t startTime = millis();
|
||||||
uint16_t needRead;
|
uint16_t needRead;
|
||||||
|
|
||||||
while (millis() - startTime < 800) {
|
while (millis() - startTime < 1200) {
|
||||||
while (_serial_gps->available()) {
|
while (_serial_gps->available()) {
|
||||||
int c = _serial_gps->read();
|
int c = _serial_gps->read();
|
||||||
switch (ubxFrameCounter) {
|
switch (ubxFrameCounter) {
|
||||||
@@ -108,12 +136,12 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
// Payload lenght lsb
|
// Payload length lsb
|
||||||
needRead = c;
|
needRead = c;
|
||||||
ubxFrameCounter++;
|
ubxFrameCounter++;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
// Payload lenght msb
|
// Payload length msb
|
||||||
needRead |= (c << 8);
|
needRead |= (c << 8);
|
||||||
ubxFrameCounter++;
|
ubxFrameCounter++;
|
||||||
break;
|
break;
|
||||||
@@ -126,7 +154,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
|
|||||||
if (_serial_gps->readBytes(buffer, needRead) != needRead) {
|
if (_serial_gps->readBytes(buffer, needRead) != needRead) {
|
||||||
ubxFrameCounter = 0;
|
ubxFrameCounter = 0;
|
||||||
} else {
|
} else {
|
||||||
// return payload lenght
|
// return payload length
|
||||||
return needRead;
|
return needRead;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -146,7 +174,7 @@ bool GPS::setupGPS()
|
|||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
// In esp32 framework, setRxBufferSize needs to be initialized before Serial
|
// In esp32 framework, setRxBufferSize needs to be initialized before Serial
|
||||||
_serial_gps->setRxBufferSize(2048); // the default is 256
|
_serial_gps->setRxBufferSize(SERIAL_BUFFER_SIZE); // the default is 256
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// if the overrides are not dialled in, set them from the board definitions, if they exist
|
// if the overrides are not dialled in, set them from the board definitions, if they exist
|
||||||
@@ -160,10 +188,14 @@ bool GPS::setupGPS()
|
|||||||
config.position.tx_gpio = GPS_TX_PIN;
|
config.position.tx_gpio = GPS_TX_PIN;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//#define BAUD_RATE 115200
|
||||||
// ESP32 has a special set of parameters vs other arduino ports
|
// ESP32 has a special set of parameters vs other arduino ports
|
||||||
#if defined(ARCH_ESP32)
|
#if defined(ARCH_ESP32)
|
||||||
if (config.position.rx_gpio)
|
if (config.position.rx_gpio) {
|
||||||
|
LOG_DEBUG("Using GPIO%d for GPS RX\n", config.position.rx_gpio);
|
||||||
|
LOG_DEBUG("Using GPIO%d for GPS TX\n", config.position.tx_gpio);
|
||||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, config.position.rx_gpio, config.position.tx_gpio);
|
_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
|
||||||
@@ -181,8 +213,8 @@ bool GPS::setupGPS()
|
|||||||
// _serial_gps->begin(9600); //The baud rate of 9600 has been initialized at the beginning of setupGPS, this line
|
// _serial_gps->begin(9600); //The baud rate of 9600 has been initialized at the beginning of setupGPS, this line
|
||||||
// is the redundant part delay(250);
|
// is the redundant part delay(250);
|
||||||
|
|
||||||
// Initialize the L76K Chip, use GPS + GLONASS
|
// Initialize the L76K Chip, use GPS + GLONASS + BEIDOU
|
||||||
_serial_gps->write("$PCAS04,5*1C\r\n");
|
_serial_gps->write("$PCAS04,7*1E\r\n");
|
||||||
delay(250);
|
delay(250);
|
||||||
// only ask for RMC and GGA
|
// only ask for RMC and GGA
|
||||||
_serial_gps->write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
|
_serial_gps->write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
|
||||||
@@ -190,8 +222,131 @@ bool GPS::setupGPS()
|
|||||||
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
|
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
|
||||||
_serial_gps->write("$PCAS11,3*1E\r\n");
|
_serial_gps->write("$PCAS11,3*1E\r\n");
|
||||||
delay(250);
|
delay(250);
|
||||||
|
} else if (gnssModel == GNSS_MODEL_UC6850) {
|
||||||
|
|
||||||
|
// use GPS + GLONASS
|
||||||
|
_serial_gps->write("$CFGSYS,h15\r\n");
|
||||||
|
delay(250);
|
||||||
} else if (gnssModel == GNSS_MODEL_UBLOX) {
|
} else if (gnssModel == GNSS_MODEL_UBLOX) {
|
||||||
|
|
||||||
|
// Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command)
|
||||||
|
// We need set it because by default it is GPS only, and we want to use GLONASS too
|
||||||
|
// Also we need SBAS for better accuracy and extra features
|
||||||
|
// ToDo: Dynamic configure GNSS systems depending of LoRa region
|
||||||
|
byte _message_GNSS[36] = {
|
||||||
|
0xb5, 0x62, // Sync message for UBX protocol
|
||||||
|
0x06, 0x3e, // Message class and ID (UBX-CFG-GNSS)
|
||||||
|
0x1c, 0x00, // Length of payload (28 bytes)
|
||||||
|
0x00, // msgVer (0 for this version)
|
||||||
|
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
|
||||||
|
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
|
||||||
|
0x03, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
|
||||||
|
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
|
||||||
|
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, // GPS
|
||||||
|
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, // SBAS
|
||||||
|
0x06, 0x08, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x01, // GLONASS
|
||||||
|
0x00, 0x00 // Checksum (to be calculated below)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate the checksum and update the message.
|
||||||
|
UBXChecksum(_message_GNSS, sizeof(_message_GNSS));
|
||||||
|
|
||||||
|
// Send the message to the module
|
||||||
|
_serial_gps->write(_message_GNSS, sizeof(_message_GNSS));
|
||||||
|
|
||||||
|
if (!getACK(0x06, 0x3e)) {
|
||||||
|
// It's not critical if the module doesn't acknowledge this configuration.
|
||||||
|
// The module should operate adequately with its factory or previously saved settings.
|
||||||
|
// It appears that there is a firmware bug in some GPS modules: When an attempt is made
|
||||||
|
// to overwrite a saved state with identical values, no ACK/NAK is received, contrary to
|
||||||
|
// what is specified in the Ublox documentation.
|
||||||
|
// There is also a possibility that the module may be GPS-only.
|
||||||
|
LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
LOG_INFO("GNSS configured for GPS+SBAS+GLONASS. Pause for 0.75s before sending next command.\n");
|
||||||
|
// Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next commands
|
||||||
|
delay(750);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable interference resistance, because we are using LoRa, WiFi and Bluetooth on same board,
|
||||||
|
// and we need to reduce interference from them
|
||||||
|
byte _message_JAM[16] = {
|
||||||
|
0xB5, 0x62, // UBX protocol sync characters
|
||||||
|
0x06, 0x39, // Message class and ID (UBX-CFG-ITFM)
|
||||||
|
0x08, 0x00, // Length of payload (8 bytes)
|
||||||
|
// bbThreshold (Broadband jamming detection threshold) is set to 0x3F (63 in decimal)
|
||||||
|
// cwThreshold (CW jamming detection threshold) is set to 0x10 (16 in decimal)
|
||||||
|
// algorithmBits (Reserved algorithm settings) is set to 0x16B156 as recommended
|
||||||
|
// enable (Enable interference detection) is set to 1 (enabled)
|
||||||
|
0x3F, 0x10, 0xB1, 0x56, // config: Interference config word
|
||||||
|
// generalBits (General settings) is set to 0x31E as recommended
|
||||||
|
// antSetting (Antenna setting, 0=unknown, 1=passive, 2=active) is set to 0 (unknown)
|
||||||
|
// ToDo: Set to 1 (passive) or 2 (active) if known, for example from UBX-MON-HW, or from board info
|
||||||
|
// enable2 (Set to 1 to scan auxiliary bands, u-blox 8 / u-blox M8 only, otherwise ignored) is set to 1
|
||||||
|
// (enabled)
|
||||||
|
0x1E, 0x03, 0x00, 0x01, // config2: Extra settings for jamming/interference monitor
|
||||||
|
0x00, 0x00 // Checksum (calculated below)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate the checksum and update the message.
|
||||||
|
UBXChecksum(_message_JAM, sizeof(_message_JAM));
|
||||||
|
|
||||||
|
// Send the message to the module
|
||||||
|
_serial_gps->write(_message_JAM, sizeof(_message_JAM));
|
||||||
|
|
||||||
|
if (!getACK(0x06, 0x39)) {
|
||||||
|
LOG_WARN("Unable to enable interference resistance.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure navigation engine expert settings:
|
||||||
|
byte _message_NAVX5[48] = {
|
||||||
|
0xb5, 0x62, // UBX protocol sync characters
|
||||||
|
0x06, 0x23, // Message class and ID (UBX-CFG-NAVX5)
|
||||||
|
0x28, 0x00, // Length of payload (40 bytes)
|
||||||
|
0x00, 0x00, // msgVer (0 for this version)
|
||||||
|
// minMax flag = 1: apply min/max SVs settings
|
||||||
|
// minCno flag = 1: apply minimum C/N0 setting
|
||||||
|
// initial3dfix flag = 0: apply initial 3D fix settings
|
||||||
|
// aop flag = 1: apply aopCfg (useAOP flag) settings (AssistNow Autonomous)
|
||||||
|
0x1B, 0x00, // mask1 (First parameters bitmask)
|
||||||
|
// adr flag = 0: apply ADR sensor fusion on/off setting (useAdr flag)
|
||||||
|
// If firmware is not ADR/UDR, enabling this flag will fail configuration
|
||||||
|
// ToDo: check this with UBX-MON-VER
|
||||||
|
0x00, 0x00, 0x00, 0x00, // mask2 (Second parameters bitmask)
|
||||||
|
0x00, 0x00, // Reserved
|
||||||
|
0x03, // minSVs (Minimum number of satellites for navigation) = 3
|
||||||
|
0x10, // maxSVs (Maximum number of satellites for navigation) = 16
|
||||||
|
0x06, // minCNO (Minimum satellite signal level for navigation) = 6 dBHz
|
||||||
|
0x00, // Reserved
|
||||||
|
0x00, // iniFix3D (Initial fix must be 3D) = 0 (disabled)
|
||||||
|
0x00, 0x00, // Reserved
|
||||||
|
0x00, // ackAiding (Issue acknowledgements for assistance message input) = 0 (disabled)
|
||||||
|
0x00, 0x00, // Reserved
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved
|
||||||
|
0x00, // Reserved
|
||||||
|
0x01, // aopCfg (AssistNow Autonomous configuration) = 1 (enabled)
|
||||||
|
0x00, 0x00, // Reserved
|
||||||
|
0x00, 0x00, // Reserved
|
||||||
|
0x00, 0x00, 0x00, 0x00, // Reserved
|
||||||
|
0x00, 0x00, 0x00, // Reserved
|
||||||
|
0x01, // useAdr (Enable/disable ADR sensor fusion) = 1 (enabled)
|
||||||
|
0x00, 0x00 // Checksum (calculated below)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate the checksum and update the message.
|
||||||
|
UBXChecksum(_message_NAVX5, sizeof(_message_NAVX5));
|
||||||
|
|
||||||
|
// Send the message to the module
|
||||||
|
_serial_gps->write(_message_NAVX5, sizeof(_message_NAVX5));
|
||||||
|
|
||||||
|
if (!getACK(0x06, 0x23)) {
|
||||||
|
LOG_WARN("Unable to configure extra settings.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after
|
tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after
|
||||||
setting will not output command messages in UART1, resulting in unrecognized module information
|
setting will not output command messages in UART1, resulting in unrecognized module information
|
||||||
@@ -208,57 +363,205 @@ bool GPS::setupGPS()
|
|||||||
|
|
||||||
// ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid
|
// ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid
|
||||||
|
|
||||||
// disable GGL
|
// Set GPS update rate to 1Hz
|
||||||
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01,
|
// Lowering the update rate helps to save power.
|
||||||
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A};
|
// Additionally, for some new modules like the M9/M10, an update rate lower than 5Hz
|
||||||
|
// is recommended to avoid a known issue with satellites disappearing.
|
||||||
|
byte _message_1Hz[] = {
|
||||||
|
0xB5, 0x62, // UBX protocol sync characters
|
||||||
|
0x06, 0x08, // Message class and ID (UBX-CFG-RATE)
|
||||||
|
0x06, 0x00, // Length of payload (6 bytes)
|
||||||
|
0xE8, 0x03, // Measurement Rate (1000ms for 1Hz)
|
||||||
|
0x01, 0x00, // Navigation rate, always 1 in GPS mode
|
||||||
|
0x01, 0x00, // Time reference
|
||||||
|
0x00, 0x00 // Placeholder for checksum, will be calculated next
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate the checksum and update the message.
|
||||||
|
UBXChecksum(_message_1Hz, sizeof(_message_1Hz));
|
||||||
|
|
||||||
|
// Send the message to the module
|
||||||
|
_serial_gps->write(_message_1Hz, sizeof(_message_1Hz));
|
||||||
|
|
||||||
|
if (!getACK(0x06, 0x08)) {
|
||||||
|
LOG_WARN("Unable to set GPS update rate.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable GGL. GGL - Geographic position (latitude and longitude), which provides the current geographical
|
||||||
|
// coordinates.
|
||||||
|
byte _message_GGL[] = {
|
||||||
|
0xB5, 0x62, // UBX sync characters
|
||||||
|
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||||
|
0x08, 0x00, // Length of payload (8 bytes)
|
||||||
|
0xF0, 0x01, // NMEA ID for GLL
|
||||||
|
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||||
|
0x00, // Disable
|
||||||
|
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||||
|
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate the checksum and update the message.
|
||||||
|
UBXChecksum(_message_GGL, sizeof(_message_GGL));
|
||||||
|
|
||||||
|
// Send the message to the module
|
||||||
_serial_gps->write(_message_GGL, sizeof(_message_GGL));
|
_serial_gps->write(_message_GGL, sizeof(_message_GGL));
|
||||||
|
|
||||||
if (!getACK(0x06, 0x01)) {
|
if (!getACK(0x06, 0x01)) {
|
||||||
LOG_WARN("Unable to disable NMEA GGL.\n");
|
LOG_WARN("Unable to disable NMEA GGL.\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable GSA
|
// Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
|
||||||
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02,
|
// the DOP (Dilution of Precision)
|
||||||
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41};
|
byte _message_GSA[] = {
|
||||||
|
0xB5, 0x62, // UBX sync characters
|
||||||
|
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||||
|
0x08, 0x00, // Length of payload (8 bytes)
|
||||||
|
0xF0, 0x02, // NMEA ID for GSA
|
||||||
|
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||||
|
0x01, // Enable
|
||||||
|
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||||
|
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||||
|
};
|
||||||
|
UBXChecksum(_message_GSA, sizeof(_message_GSA));
|
||||||
_serial_gps->write(_message_GSA, sizeof(_message_GSA));
|
_serial_gps->write(_message_GSA, sizeof(_message_GSA));
|
||||||
if (!getACK(0x06, 0x01)) {
|
if (!getACK(0x06, 0x01)) {
|
||||||
LOG_WARN("Unable to disable NMEA GSA.\n");
|
LOG_WARN("Unable to Enable NMEA GSA.\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable GSV
|
// Disable GSV. GSV - Satellites in view, details the number and location of satellites in view.
|
||||||
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03,
|
byte _message_GSV[] = {
|
||||||
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48};
|
0xB5, 0x62, // UBX sync characters
|
||||||
|
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||||
|
0x08, 0x00, // Length of payload (8 bytes)
|
||||||
|
0xF0, 0x03, // NMEA ID for GSV
|
||||||
|
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||||
|
0x00, // Disable
|
||||||
|
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||||
|
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||||
|
};
|
||||||
|
UBXChecksum(_message_GSV, sizeof(_message_GSV));
|
||||||
_serial_gps->write(_message_GSV, sizeof(_message_GSV));
|
_serial_gps->write(_message_GSV, sizeof(_message_GSV));
|
||||||
if (!getACK(0x06, 0x01)) {
|
if (!getACK(0x06, 0x01)) {
|
||||||
LOG_WARN("Unable to disable NMEA GSV.\n");
|
LOG_WARN("Unable to disable NMEA GSV.\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable VTG
|
// Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to
|
||||||
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05,
|
// the ground.
|
||||||
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56};
|
byte _message_VTG[] = {
|
||||||
|
0xB5, 0x62, // UBX sync characters
|
||||||
|
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||||
|
0x08, 0x00, // Length of payload (8 bytes)
|
||||||
|
0xF0, 0x05, // NMEA ID for VTG
|
||||||
|
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||||
|
0x00, // Disable
|
||||||
|
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||||
|
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||||
|
};
|
||||||
|
UBXChecksum(_message_VTG, sizeof(_message_VTG));
|
||||||
_serial_gps->write(_message_VTG, sizeof(_message_VTG));
|
_serial_gps->write(_message_VTG, sizeof(_message_VTG));
|
||||||
if (!getACK(0x06, 0x01)) {
|
if (!getACK(0x06, 0x01)) {
|
||||||
LOG_WARN("Unable to disable NMEA VTG.\n");
|
LOG_WARN("Unable to disable NMEA VTG.\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable RMC
|
// Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data.
|
||||||
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04,
|
byte _message_RMC[] = {
|
||||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54};
|
0xB5, 0x62, // UBX sync characters
|
||||||
|
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||||
|
0x08, 0x00, // Length of payload (8 bytes)
|
||||||
|
0xF0, 0x04, // NMEA ID for RMC
|
||||||
|
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||||
|
0x01, // Enable
|
||||||
|
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||||
|
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||||
|
};
|
||||||
|
UBXChecksum(_message_RMC, sizeof(_message_RMC));
|
||||||
_serial_gps->write(_message_RMC, sizeof(_message_RMC));
|
_serial_gps->write(_message_RMC, sizeof(_message_RMC));
|
||||||
if (!getACK(0x06, 0x01)) {
|
if (!getACK(0x06, 0x01)) {
|
||||||
LOG_WARN("Unable to enable NMEA RMC.\n");
|
LOG_WARN("Unable to enable NMEA RMC.\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable GGA
|
// Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data.
|
||||||
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00,
|
byte _message_GGA[] = {
|
||||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38};
|
0xB5, 0x62, // UBX sync characters
|
||||||
|
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||||
|
0x08, 0x00, // Length of payload (8 bytes)
|
||||||
|
0xF0, 0x00, // NMEA ID for GGA
|
||||||
|
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||||
|
0x01, // Enable
|
||||||
|
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||||
|
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||||
|
};
|
||||||
|
UBXChecksum(_message_GGA, sizeof(_message_GGA));
|
||||||
_serial_gps->write(_message_GGA, sizeof(_message_GGA));
|
_serial_gps->write(_message_GGA, sizeof(_message_GGA));
|
||||||
if (!getACK(0x06, 0x01)) {
|
if (!getACK(0x06, 0x01)) {
|
||||||
LOG_WARN("Unable to enable NMEA GGA.\n");
|
LOG_WARN("Unable to enable NMEA GGA.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Power Management configuration allows the GPS module to operate in different power modes for optimized power
|
||||||
|
// consumption.
|
||||||
|
// The modes supported are:
|
||||||
|
// 0x00 = Full power: The module operates at full power with no power saving.
|
||||||
|
// 0x01 = Balanced: The module dynamically adjusts the tracking behavior to balance power consumption.
|
||||||
|
// 0x02 = Interval: The module operates in a periodic mode, cycling between tracking and power saving states.
|
||||||
|
// 0x03 = Aggressive with 1 Hz: The module operates in a power saving mode with a 1 Hz update rate.
|
||||||
|
// 0x04 = Aggressive with 2 Hz: The module operates in a power saving mode with a 2 Hz update rate.
|
||||||
|
// 0x05 = Aggressive with 4 Hz: The module operates in a power saving mode with a 4 Hz update rate.
|
||||||
|
// The 'period' field specifies the position update and search period. It is only valid when the powerSetupValue is
|
||||||
|
// set to Interval; otherwise, it must be set to '0'. The 'onTime' field specifies the duration of the ON phase and
|
||||||
|
// must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise, it must
|
||||||
|
// be set to '0'.
|
||||||
|
byte UBX_CFG_PMS[14] = {
|
||||||
|
0xB5, 0x62, // UBX sync characters
|
||||||
|
0x06, 0x86, // Message class and ID (UBX-CFG-PMS)
|
||||||
|
0x06, 0x00, // Length of payload (6 bytes)
|
||||||
|
0x00, // Version (0)
|
||||||
|
0x03, // Power setup value
|
||||||
|
0x00, 0x00, // period: not applicable, set to 0
|
||||||
|
0x00, 0x00, // onTime: not applicable, set to 0
|
||||||
|
0x00, 0x00 // Placeholder for checksum, will be calculated next
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate the checksum and update the message
|
||||||
|
UBXChecksum(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
|
||||||
|
|
||||||
|
// Send the message to the module
|
||||||
|
_serial_gps->write(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
|
||||||
|
if (!getACK(0x06, 0x86)) {
|
||||||
|
LOG_WARN("Unable to enable powersaving for GPS.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need save configuration to flash to make our config changes persistent
|
||||||
|
byte _message_SAVE[21] = {
|
||||||
|
0xB5, 0x62, // UBX protocol header
|
||||||
|
0x06, 0x09, // UBX class ID (Configuration Input Messages), message ID (UBX-CFG-CFG)
|
||||||
|
0x0D, 0x00, // Length of payload (13 bytes)
|
||||||
|
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
|
||||||
|
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
|
||||||
|
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
|
||||||
|
0x0F, // deviceMask: BBR, Flash, EEPROM, and SPI Flash
|
||||||
|
0x00, 0x00 // Checksum (calculated below)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate the checksum and update the message.
|
||||||
|
UBXChecksum(_message_SAVE, sizeof(_message_SAVE));
|
||||||
|
|
||||||
|
// Send the message to the module
|
||||||
|
_serial_gps->write(_message_SAVE, sizeof(_message_SAVE));
|
||||||
|
|
||||||
|
if (!getACK(0x06, 0x09)) {
|
||||||
|
LOG_WARN("Unable to save GNSS module configuration.\n");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
LOG_INFO("GNSS module configuration saved!\n");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,22 +572,21 @@ bool GPS::setupGPS()
|
|||||||
bool GPS::setup()
|
bool GPS::setup()
|
||||||
{
|
{
|
||||||
// Master power for the GPS
|
// Master power for the GPS
|
||||||
#ifdef PIN_GPS_EN
|
|
||||||
digitalWrite(PIN_GPS_EN, 1);
|
|
||||||
pinMode(PIN_GPS_EN, OUTPUT);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAS_PMU
|
#if defined(HAS_PMU) || defined(PIN_GPS_EN)
|
||||||
if (config.position.gps_enabled) {
|
if (config.position.gps_enabled) {
|
||||||
|
#ifdef PIN_GPS_EN
|
||||||
|
pinMode(PIN_GPS_EN, OUTPUT);
|
||||||
|
#endif
|
||||||
setGPSPower(true);
|
setGPSPower(true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PIN_GPS_RESET
|
#ifdef PIN_GPS_RESET
|
||||||
digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms
|
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||||
delay(10);
|
delay(10);
|
||||||
digitalWrite(PIN_GPS_RESET, 0);
|
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||||
#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();
|
||||||
@@ -384,7 +686,7 @@ void GPS::setAwake(bool on)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get how long we should stay looking for each aquisition in msecs
|
/** Get how long we should stay looking for each acquisition in msecs
|
||||||
*/
|
*/
|
||||||
uint32_t GPS::getWakeTime() const
|
uint32_t GPS::getWakeTime() const
|
||||||
{
|
{
|
||||||
@@ -503,15 +805,6 @@ int32_t GPS::runOnce()
|
|||||||
|
|
||||||
// If state has changed do a publish
|
// If state has changed do a publish
|
||||||
publishUpdate();
|
publishUpdate();
|
||||||
|
|
||||||
if (!(fixeddelayCtr >= 20) && config.position.fixed_position && hasValidLocation) {
|
|
||||||
fixeddelayCtr++;
|
|
||||||
// LOG_DEBUG("Our delay counter is %d\n", fixeddelayCtr);
|
|
||||||
if (fixeddelayCtr >= 20) {
|
|
||||||
doGPSpowersave(false);
|
|
||||||
forceWake(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
|
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
|
||||||
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
|
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
|
||||||
return isAwake ? GPS_THREAD_INTERVAL : 5000;
|
return isAwake ? GPS_THREAD_INTERVAL : 5000;
|
||||||
@@ -532,6 +825,14 @@ void GPS::forceWake(bool on)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear the GPS rx buffer as quickly as possible
|
||||||
|
void GPS::clearBuffer()
|
||||||
|
{
|
||||||
|
int x = _serial_gps->available();
|
||||||
|
while (x--)
|
||||||
|
_serial_gps->read();
|
||||||
|
}
|
||||||
|
|
||||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||||
int GPS::prepareSleep(void *unused)
|
int GPS::prepareSleep(void *unused)
|
||||||
{
|
{
|
||||||
@@ -555,21 +856,17 @@ int GPS::prepareDeepSleep(void *unused)
|
|||||||
|
|
||||||
GnssModel_t GPS::probe()
|
GnssModel_t GPS::probe()
|
||||||
{
|
{
|
||||||
// return immediately if the model is set by the variant.h file
|
|
||||||
#ifdef GPS_UBLOX
|
|
||||||
return GNSS_MODEL_UBLOX;
|
|
||||||
#elif defined(GPS_L76K)
|
|
||||||
return GNSS_MODEL_MTK;
|
|
||||||
#else
|
|
||||||
// we use autodetect, only T-BEAM S3 for now...
|
|
||||||
uint8_t buffer[256];
|
|
||||||
/*
|
|
||||||
* The GNSS module information variable is temporarily placed inside the function body,
|
|
||||||
* if it needs to be used elsewhere, it can be moved to the outside
|
|
||||||
* */
|
|
||||||
struct uBloxGnssModelInfo info;
|
|
||||||
|
|
||||||
memset(&info, 0, sizeof(struct uBloxGnssModelInfo));
|
memset(&info, 0, sizeof(struct uBloxGnssModelInfo));
|
||||||
|
// return immediately if the model is set by the variant.h file
|
||||||
|
//#ifdef GPS_UBLOX (unless it's a ublox, because we might want to know the module info!
|
||||||
|
// return GNSS_MODEL_UBLOX; think about removing this macro and return)
|
||||||
|
#if defined(GPS_L76K)
|
||||||
|
return GNSS_MODEL_MTK;
|
||||||
|
#elif defined(GPS_UC6580)
|
||||||
|
_serial_gps->updateBaudRate(115200);
|
||||||
|
return GNSS_MODEL_UC6850;
|
||||||
|
#else
|
||||||
|
uint8_t buffer[384] = {0};
|
||||||
|
|
||||||
// Close all NMEA sentences , Only valid for MTK platform
|
// Close all NMEA sentences , Only valid for MTK platform
|
||||||
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||||
@@ -586,7 +883,7 @@ GnssModel_t GPS::probe()
|
|||||||
int index = ver.indexOf("$");
|
int index = ver.indexOf("$");
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
ver = ver.substring(index);
|
ver = ver.substring(index);
|
||||||
if (ver.startsWith("$GPTXT,01,01,02")) {
|
if (ver.startsWith("$GPTXT,01,01,02,SW=")) {
|
||||||
LOG_INFO("L76K GNSS init succeeded, using L76K GNSS Module\n");
|
LOG_INFO("L76K GNSS init succeeded, using L76K GNSS Module\n");
|
||||||
return GNSS_MODEL_MTK;
|
return GNSS_MODEL_MTK;
|
||||||
}
|
}
|
||||||
@@ -597,31 +894,37 @@ GnssModel_t GPS::probe()
|
|||||||
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
|
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
|
||||||
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
|
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
|
||||||
// Check that the returned response class and message ID are correct
|
// Check that the returned response class and message ID are correct
|
||||||
if (!getAck(buffer, 256, 0x06, 0x08)) {
|
if (!getAck(buffer, 384, 0x06, 0x08)) {
|
||||||
LOG_WARN("Failed to find UBlox & MTK GNSS Module\n");
|
LOG_WARN("Failed to find UBlox & MTK GNSS Module\n");
|
||||||
return GNSS_MODEL_UNKONW;
|
return GNSS_MODEL_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
byte _message_MONVER[8] = {
|
||||||
|
0xB5, 0x62, // Sync message for UBX protocol
|
||||||
|
0x0A, 0x04, // Message class and ID (UBX-MON-VER)
|
||||||
|
0x00, 0x00, // Length of payload (we're asking for an answer, so no payload)
|
||||||
|
0x00, 0x00 // Checksum
|
||||||
|
};
|
||||||
// Get Ublox gnss module hardware and software info
|
// Get Ublox gnss module hardware and software info
|
||||||
uint8_t cfg_get_hw[] = {0xB5, 0x62, 0x0A, 0x04, 0x00, 0x00, 0x0E, 0x34};
|
UBXChecksum(_message_MONVER, sizeof(_message_MONVER));
|
||||||
_serial_gps->write(cfg_get_hw, sizeof(cfg_get_hw));
|
_serial_gps->write(_message_MONVER, sizeof(_message_MONVER));
|
||||||
|
|
||||||
uint16_t len = getAck(buffer, 256, 0x0A, 0x04);
|
uint16_t len = getAck(buffer, 384, 0x0A, 0x04);
|
||||||
if (len) {
|
if (len) {
|
||||||
|
// LOG_DEBUG("monver reply size = %d\n", len);
|
||||||
uint16_t position = 0;
|
uint16_t position = 0;
|
||||||
for (int i = 0; i < 30; i++) {
|
for (int i = 0; i < 30; i++) {
|
||||||
info.swVersion[i] = buffer[position];
|
info.swVersion[i] = buffer[position];
|
||||||
position++;
|
position++;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
info.hwVersion[i] = buffer[position];
|
info.hwVersion[i] = buffer[position - 1];
|
||||||
position++;
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (len >= position + 30) {
|
while (len >= position + 30) {
|
||||||
for (int i = 0; i < 30; i++) {
|
for (int i = 0; i < 30; i++) {
|
||||||
info.extension[info.extensionNo][i] = buffer[position];
|
info.extension[info.extensionNo][i] = buffer[position - 1];
|
||||||
position++;
|
position++;
|
||||||
}
|
}
|
||||||
info.extensionNo++;
|
info.extensionNo++;
|
||||||
@@ -631,6 +934,7 @@ GnssModel_t GPS::probe()
|
|||||||
|
|
||||||
LOG_DEBUG("Module Info : \n");
|
LOG_DEBUG("Module Info : \n");
|
||||||
LOG_DEBUG("Soft version: %s\n", info.swVersion);
|
LOG_DEBUG("Soft version: %s\n", info.swVersion);
|
||||||
|
LOG_DEBUG("first char is %c\n", (char)info.swVersion[0]);
|
||||||
LOG_DEBUG("Hard version: %s\n", info.hwVersion);
|
LOG_DEBUG("Hard version: %s\n", info.hwVersion);
|
||||||
LOG_DEBUG("Extensions:%d\n", info.extensionNo);
|
LOG_DEBUG("Extensions:%d\n", info.extensionNo);
|
||||||
for (int i = 0; i < info.extensionNo; i++) {
|
for (int i = 0; i < info.extensionNo; i++) {
|
||||||
@@ -641,19 +945,29 @@ GnssModel_t GPS::probe()
|
|||||||
|
|
||||||
// tips: extensionNo field is 0 on some 6M GNSS modules
|
// tips: extensionNo field is 0 on some 6M GNSS modules
|
||||||
for (int i = 0; i < info.extensionNo; ++i) {
|
for (int i = 0; i < info.extensionNo; ++i) {
|
||||||
if (!strncmp(info.extension[i], "OD=", 3)) {
|
if (!strncmp(info.extension[i], "MOD=", 4)) {
|
||||||
strncpy((char *)buffer, &(info.extension[i][3]), sizeof(buffer));
|
strncpy((char *)buffer, &(info.extension[i][4]), sizeof(buffer));
|
||||||
LOG_DEBUG("GetModel:%s\n", (char *)buffer);
|
// LOG_DEBUG("GetModel:%s\n", (char *)buffer);
|
||||||
|
if (strlen((char *)buffer)) {
|
||||||
|
LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n", (char *)buffer);
|
||||||
|
} else {
|
||||||
|
LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
|
||||||
|
}
|
||||||
|
} else if (!strncmp(info.extension[i], "PROTVER=", 8)) {
|
||||||
|
char *ptr = nullptr;
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
strncpy((char *)buffer, &(info.extension[i][8]), sizeof(buffer));
|
||||||
|
LOG_DEBUG("Protocol Version:%s\n", (char *)buffer);
|
||||||
|
if (strlen((char *)buffer)) {
|
||||||
|
uBloxProtocolVersion = strtoul((char *)buffer, &ptr, 10);
|
||||||
|
LOG_DEBUG("ProtVer=%d\n", uBloxProtocolVersion);
|
||||||
|
} else {
|
||||||
|
uBloxProtocolVersion = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen((char *)buffer)) {
|
|
||||||
LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n", buffer);
|
|
||||||
} else {
|
|
||||||
LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return GNSS_MODEL_UBLOX;
|
return GNSS_MODEL_UBLOX;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -675,8 +989,8 @@ GPS *createGps()
|
|||||||
LOG_DEBUG("Using MSL altitude model\n");
|
LOG_DEBUG("Using MSL altitude model\n");
|
||||||
#endif
|
#endif
|
||||||
if (GPS::_serial_gps) {
|
if (GPS::_serial_gps) {
|
||||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all.
|
||||||
// assume NMEA at 9600 baud.
|
// Just assume NMEA at 9600 baud.
|
||||||
GPS *new_gps = new NMEAGPS();
|
GPS *new_gps = new NMEAGPS();
|
||||||
new_gps->setup();
|
new_gps->setup();
|
||||||
return new_gps;
|
return new_gps;
|
||||||
@@ -688,4 +1002,4 @@ GPS *createGps()
|
|||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,8 @@ struct uBloxGnssModelInfo {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
GNSS_MODEL_MTK,
|
GNSS_MODEL_MTK,
|
||||||
GNSS_MODEL_UBLOX,
|
GNSS_MODEL_UBLOX,
|
||||||
GNSS_MODEL_UNKONW,
|
GNSS_MODEL_UC6850,
|
||||||
|
GNSS_MODEL_UNKNOWN,
|
||||||
} GnssModel_t;
|
} GnssModel_t;
|
||||||
|
|
||||||
// Generate a string representation of DOP
|
// Generate a string representation of DOP
|
||||||
@@ -90,6 +91,9 @@ class GPS : private concurrency::OSThread
|
|||||||
// Some GPS modules (ublock) require factory reset
|
// Some GPS modules (ublock) require factory reset
|
||||||
virtual bool factoryReset() { return true; }
|
virtual bool factoryReset() { return true; }
|
||||||
|
|
||||||
|
// Empty the input buffer as quickly as possible
|
||||||
|
void clearBuffer();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Do gps chipset specific init, return true for success
|
/// Do gps chipset specific init, return true for success
|
||||||
virtual bool setupGPS();
|
virtual bool setupGPS();
|
||||||
@@ -139,6 +143,9 @@ class GPS : private concurrency::OSThread
|
|||||||
/// always returns 0 to indicate okay to sleep
|
/// always returns 0 to indicate okay to sleep
|
||||||
int prepareDeepSleep(void *unused);
|
int prepareDeepSleep(void *unused);
|
||||||
|
|
||||||
|
// Calculate checksum
|
||||||
|
void UBXChecksum(byte *message, size_t length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
|
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
|
||||||
*
|
*
|
||||||
@@ -164,6 +171,7 @@ class GPS : private concurrency::OSThread
|
|||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
// Get GNSS model
|
// Get GNSS model
|
||||||
|
String getNMEA();
|
||||||
GnssModel_t probe();
|
GnssModel_t probe();
|
||||||
|
|
||||||
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
|
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
|
||||||
@@ -172,11 +180,11 @@ class GPS : private concurrency::OSThread
|
|||||||
uint8_t fixeddelayCtr = 0;
|
uint8_t fixeddelayCtr = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GnssModel_t gnssModel = GNSS_MODEL_UNKONW;
|
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Creates an instance of the GPS class.
|
// Creates an instance of the GPS class.
|
||||||
// Returns the new instance or null if the GPS is not present.
|
// Returns the new instance or null if the GPS is not present.
|
||||||
GPS *createGps();
|
GPS *createGps();
|
||||||
|
|
||||||
extern GPS *gps;
|
extern GPS *gps;
|
||||||
@@ -12,7 +12,7 @@ GeoCoord::GeoCoord(int32_t lat, int32_t lon, int32_t alt) : _latitude(lat), _lon
|
|||||||
|
|
||||||
GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt)
|
GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt)
|
||||||
{
|
{
|
||||||
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
|
// Change decimial representation to int32_t. I.e., 12.345 becomes 123450000
|
||||||
_latitude = int32_t(lat * 1e+7);
|
_latitude = int32_t(lat * 1e+7);
|
||||||
_longitude = int32_t(lon * 1e+7);
|
_longitude = int32_t(lon * 1e+7);
|
||||||
GeoCoord::setCoords();
|
GeoCoord::setCoords();
|
||||||
@@ -20,7 +20,7 @@ GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt)
|
|||||||
|
|
||||||
GeoCoord::GeoCoord(double lat, double lon, int32_t alt) : _altitude(alt)
|
GeoCoord::GeoCoord(double lat, double lon, int32_t alt) : _altitude(alt)
|
||||||
{
|
{
|
||||||
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
|
// Change decimial representation to int32_t. I.e., 12.345 becomes 123450000
|
||||||
_latitude = int32_t(lat * 1e+7);
|
_latitude = int32_t(lat * 1e+7);
|
||||||
_longitude = int32_t(lon * 1e+7);
|
_longitude = int32_t(lon * 1e+7);
|
||||||
GeoCoord::setCoords();
|
GeoCoord::setCoords();
|
||||||
@@ -41,7 +41,7 @@ void GeoCoord::setCoords()
|
|||||||
|
|
||||||
void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt)
|
void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt)
|
||||||
{
|
{
|
||||||
// If marked dirty or new coordiantes
|
// If marked dirty or new coordinates
|
||||||
if (_dirty || _latitude != lat || _longitude != lon || _altitude != alt) {
|
if (_dirty || _latitude != lat || _longitude != lon || _altitude != alt) {
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
_latitude = lat;
|
_latitude = lat;
|
||||||
@@ -55,7 +55,7 @@ void GeoCoord::updateCoords(const double lat, const double lon, const int32_t al
|
|||||||
{
|
{
|
||||||
int32_t iLat = lat * 1e+7;
|
int32_t iLat = lat * 1e+7;
|
||||||
int32_t iLon = lon * 1e+7;
|
int32_t iLon = lon * 1e+7;
|
||||||
// If marked dirty or new coordiantes
|
// If marked dirty or new coordinates
|
||||||
if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
|
if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
_latitude = iLat;
|
_latitude = iLat;
|
||||||
@@ -69,7 +69,7 @@ void GeoCoord::updateCoords(const float lat, const float lon, const int32_t alt)
|
|||||||
{
|
{
|
||||||
int32_t iLat = lat * 1e+7;
|
int32_t iLat = lat * 1e+7;
|
||||||
int32_t iLon = lon * 1e+7;
|
int32_t iLon = lon * 1e+7;
|
||||||
// If marked dirty or new coordiantes
|
// If marked dirty or new coordinates
|
||||||
if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
|
if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
_latitude = iLat;
|
_latitude = iLat;
|
||||||
@@ -217,7 +217,7 @@ void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr)
|
|||||||
double eta2 = v / rho - 1;
|
double eta2 = v / rho - 1;
|
||||||
double mA = (1 + n + (5 / 4) * n * n + (5 / 4) * n * n * n) * (phi - phi0);
|
double mA = (1 + n + (5 / 4) * n * n + (5 / 4) * n * n * n) * (phi - phi0);
|
||||||
double mB = (3 * n + 3 * n * n + (21 / 8) * n * n * n) * sin(phi - phi0) * cos(phi + phi0);
|
double mB = (3 * n + 3 * n * n + (21 / 8) * n * n * n) * sin(phi - phi0) * cos(phi + phi0);
|
||||||
// loss of precision in mC & mD due to floating point rounding can cause innaccuracy of northing by a few meters
|
// loss of precision in mC & mD due to floating point rounding can cause inaccuracy of northing by a few meters
|
||||||
double mC = (15 / 8 * n * n + 15 / 8 * n * n * n) * sin(2 * (phi - phi0)) * cos(2 * (phi + phi0));
|
double mC = (15 / 8 * n * n + 15 / 8 * n * n * n) * sin(2 * (phi - phi0)) * cos(2 * (phi + phi0));
|
||||||
double mD = (35 / 24) * n * n * n * sin(3 * (phi - phi0)) * cos(3 * (phi + phi0));
|
double mD = (35 / 24) * n * n * n * sin(3 * (phi - phi0)) * cos(3 * (phi + phi0));
|
||||||
double m = b * f0 * (mA - mB + mC - mD);
|
double m = b * f0 * (mA - mB + mC - mD);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ struct MGRS {
|
|||||||
uint32_t northing;
|
uint32_t northing;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A struct to hold the data for a OSGR coordiante
|
// A struct to hold the data for a OSGR coordinate
|
||||||
struct OSGR {
|
struct OSGR {
|
||||||
char e100k;
|
char e100k;
|
||||||
char n100k;
|
char n100k;
|
||||||
|
|||||||
@@ -107,6 +107,14 @@ bool NMEAGPS::lookForLocation()
|
|||||||
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
||||||
fixQual = reader.fixQuality();
|
fixQual = reader.fixQuality();
|
||||||
|
|
||||||
|
#ifndef TINYGPS_OPTION_NO_STATISTICS
|
||||||
|
if (reader.failedChecksum() > lastChecksumFailCount) {
|
||||||
|
LOG_WARN("Warning, %u new GPS checksum failures, for a total of %u.\n", reader.failedChecksum() - lastChecksumFailCount,
|
||||||
|
reader.failedChecksum());
|
||||||
|
lastChecksumFailCount = reader.failedChecksum();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
#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
|
||||||
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
|
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
|
||||||
@@ -174,8 +182,10 @@ bool NMEAGPS::lookForLocation()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Discard incomplete or erroneous readings
|
// Discard incomplete or erroneous readings
|
||||||
if (reader.hdop.value() == 0)
|
if (reader.hdop.value() == 0) {
|
||||||
|
LOG_WARN("BOGUS hdop.value() REJECTED: %d\n", reader.hdop.value());
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
p.latitude_i = toDegInt(loc.lat);
|
p.latitude_i = toDegInt(loc.lat);
|
||||||
p.longitude_i = toDegInt(loc.lng);
|
p.longitude_i = toDegInt(loc.lng);
|
||||||
@@ -243,7 +253,14 @@ bool NMEAGPS::hasFlow()
|
|||||||
bool NMEAGPS::whileIdle()
|
bool NMEAGPS::whileIdle()
|
||||||
{
|
{
|
||||||
bool isValid = false;
|
bool isValid = false;
|
||||||
|
#ifdef SERIAL_BUFFER_SIZE
|
||||||
|
if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) {
|
||||||
|
LOG_WARN("GPS Buffer full with %u bytes waiting. Flushing to avoid corruption.\n", _serial_gps->available());
|
||||||
|
clearBuffer();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// if (_serial_gps->available() > 0)
|
||||||
|
// LOG_DEBUG("GPS Bytes Waiting: %u\n", _serial_gps->available());
|
||||||
// First consume any chars that have piled up at the receiver
|
// First consume any chars that have piled up at the receiver
|
||||||
while (_serial_gps->available() > 0) {
|
while (_serial_gps->available() > 0) {
|
||||||
int c = _serial_gps->read();
|
int c = _serial_gps->read();
|
||||||
@@ -252,4 +269,4 @@ bool NMEAGPS::whileIdle()
|
|||||||
}
|
}
|
||||||
|
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,7 @@ class NMEAGPS : public GPS
|
|||||||
{
|
{
|
||||||
TinyGPSPlus reader;
|
TinyGPSPlus reader;
|
||||||
uint8_t fixQual = 0; // fix quality from GPGGA
|
uint8_t fixQual = 0; // fix quality from GPGGA
|
||||||
|
uint32_t lastChecksumFailCount = 0;
|
||||||
|
|
||||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||||
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
|
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
|
||||||
@@ -53,4 +54,4 @@ class NMEAGPS : public GPS
|
|||||||
virtual bool hasLock() override;
|
virtual bool hasLock() override;
|
||||||
|
|
||||||
virtual bool hasFlow() override;
|
virtual bool hasFlow() override;
|
||||||
};
|
};
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "NMEAWPL.h"
|
#include "NMEAWPL.h"
|
||||||
#include "GeoCoord.h"
|
#include "GeoCoord.h"
|
||||||
|
#include "RTC.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
/* -------------------------------------------
|
/* -------------------------------------------
|
||||||
* 1 2 3 4 5 6
|
* 1 2 3 4 5 6
|
||||||
@@ -16,10 +18,11 @@
|
|||||||
* -------------------------------------------
|
* -------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name)
|
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_PositionLite &pos, const char *name, bool isCaltopoMode)
|
||||||
{
|
{
|
||||||
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
|
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
|
||||||
uint32_t len = snprintf(buf, bufsz, "$GNWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", geoCoord.getDMSLatDeg(),
|
char type = isCaltopoMode ? 'P' : 'N';
|
||||||
|
uint32_t len = snprintf(buf, bufsz, "$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(),
|
||||||
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(),
|
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(),
|
||||||
geoCoord.getDMSLonDeg(), (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
|
geoCoord.getDMSLonDeg(), (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
|
||||||
geoCoord.getDMSLonCP(), name);
|
geoCoord.getDMSLonCP(), name);
|
||||||
@@ -31,6 +34,21 @@ uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name, bool isCaltopoMode)
|
||||||
|
{
|
||||||
|
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
|
||||||
|
char type = isCaltopoMode ? 'P' : 'N';
|
||||||
|
uint32_t len = snprintf(buf, bufsz, "$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(),
|
||||||
|
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(),
|
||||||
|
geoCoord.getDMSLonDeg(), (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
|
||||||
|
geoCoord.getDMSLonCP(), name);
|
||||||
|
uint32_t chk = 0;
|
||||||
|
for (uint32_t i = 1; i < len; i++) {
|
||||||
|
chk ^= buf[i];
|
||||||
|
}
|
||||||
|
len += snprintf(buf + len, bufsz - len, "*%02X\r\n", chk);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
/* -------------------------------------------
|
/* -------------------------------------------
|
||||||
* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||||
* | | | | | | | | | | | | | | |
|
* | | | | | | | | | | | | | | |
|
||||||
@@ -56,12 +74,18 @@ uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const
|
|||||||
uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos)
|
uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos)
|
||||||
{
|
{
|
||||||
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
|
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
|
||||||
uint32_t len =
|
tm *t = localtime((time_t *)&pos.timestamp);
|
||||||
snprintf(buf, bufsz, "$GNGGA,%06u.%03u,%02d%07.4f,%c,%03d%07.4f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d", pos.time / 1000,
|
if (getRTCQuality() > 0) { // use the device clock if we got time from somewhere. If not, use the GPS timestamp.
|
||||||
pos.time % 1000, geoCoord.getDMSLatDeg(), (abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6,
|
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
|
||||||
geoCoord.getDMSLatCP(), geoCoord.getDMSLonDeg(),
|
t = localtime((time_t *)&rtc_sec);
|
||||||
(abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6, geoCoord.getDMSLonCP(), pos.fix_type,
|
}
|
||||||
pos.sats_in_view, pos.HDOP, geoCoord.getAltitude(), 'M', pos.altitude_geoidal_separation, 'M', 0, 0);
|
|
||||||
|
uint32_t len = snprintf(
|
||||||
|
buf, bufsz, "$GNGGA,%02d%02d%02d.%02d,%02d%07.4f,%c,%03d%07.4f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d", t->tm_hour,
|
||||||
|
t->tm_min, t->tm_sec, pos.timestamp_millis_adjust, geoCoord.getDMSLatDeg(),
|
||||||
|
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(), geoCoord.getDMSLonDeg(),
|
||||||
|
(abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6, geoCoord.getDMSLonCP(), pos.fix_quality,
|
||||||
|
pos.sats_in_view, pos.HDOP, geoCoord.getAltitude(), 'M', pos.altitude_geoidal_separation, 'M', 0, 0);
|
||||||
|
|
||||||
uint32_t chk = 0;
|
uint32_t chk = 0;
|
||||||
for (uint32_t i = 1; i < len; i++) {
|
for (uint32_t i = 1; i < len; i++) {
|
||||||
|
|||||||
@@ -3,5 +3,6 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name);
|
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name, bool isCaltopoMode = false);
|
||||||
uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos);
|
uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_PositionLite &pos, const char *name, bool isCaltopoMode = false);
|
||||||
|
uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos);
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "detect/ScanI2C.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -16,14 +17,22 @@ static uint32_t
|
|||||||
timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
|
timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
|
||||||
static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
|
static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the current date and time from the RTC module and updates the system time.
|
||||||
|
* @return True if the RTC was successfully read and the system time was updated, false otherwise.
|
||||||
|
*/
|
||||||
void readFromRTC()
|
void readFromRTC()
|
||||||
{
|
{
|
||||||
struct timeval tv; /* btw settimeofday() is helpfull here too*/
|
struct timeval tv; /* btw settimeofday() is helpful here too*/
|
||||||
#ifdef RV3028_RTC
|
#ifdef RV3028_RTC
|
||||||
if (rtc_found == RV3028_RTC) {
|
if (rtc_found.address == RV3028_RTC) {
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
Melopero_RV3028 rtc;
|
Melopero_RV3028 rtc;
|
||||||
|
#ifdef I2C_SDA1
|
||||||
|
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
|
||||||
|
#else
|
||||||
rtc.initI2C();
|
rtc.initI2C();
|
||||||
|
#endif
|
||||||
tm t;
|
tm t;
|
||||||
t.tm_year = rtc.getYear() - 1900;
|
t.tm_year = rtc.getYear() - 1900;
|
||||||
t.tm_mon = rtc.getMonth() - 1;
|
t.tm_mon = rtc.getMonth() - 1;
|
||||||
@@ -41,14 +50,16 @@ void readFromRTC()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(PCF8563_RTC)
|
#elif defined(PCF8563_RTC)
|
||||||
if (rtc_found == PCF8563_RTC) {
|
if (rtc_found.address == PCF8563_RTC) {
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
PCF8563_Class rtc;
|
PCF8563_Class rtc;
|
||||||
#ifdef RTC_USE_WIRE1
|
|
||||||
rtc.begin(Wire1);
|
#ifdef I2C_SDA1
|
||||||
|
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
|
||||||
#else
|
#else
|
||||||
rtc.begin();
|
rtc.begin();
|
||||||
#endif
|
#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;
|
||||||
@@ -76,7 +87,15 @@ void readFromRTC()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
|
/**
|
||||||
|
* Sets the RTC (Real-Time Clock) if the provided time is of higher quality than the current RTC time.
|
||||||
|
*
|
||||||
|
* @param q The quality of the provided time.
|
||||||
|
* @param tv A pointer to a timeval struct containing the time to potentially set the RTC to.
|
||||||
|
* @return True if the RTC was set, false otherwise.
|
||||||
|
*
|
||||||
|
* If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||||
|
*/
|
||||||
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||||
{
|
{
|
||||||
static uint32_t lastSetMsec = 0;
|
static uint32_t lastSetMsec = 0;
|
||||||
@@ -103,19 +122,24 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
|||||||
|
|
||||||
// If this platform has a setable RTC, set it
|
// If this platform has a setable RTC, set it
|
||||||
#ifdef RV3028_RTC
|
#ifdef RV3028_RTC
|
||||||
if (rtc_found == RV3028_RTC) {
|
if (rtc_found.address == RV3028_RTC) {
|
||||||
Melopero_RV3028 rtc;
|
Melopero_RV3028 rtc;
|
||||||
|
#ifdef I2C_SDA1
|
||||||
|
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
|
||||||
|
#else
|
||||||
rtc.initI2C();
|
rtc.initI2C();
|
||||||
|
#endif
|
||||||
tm *t = localtime(&tv->tv_sec);
|
tm *t = localtime(&tv->tv_sec);
|
||||||
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
|
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
|
||||||
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
||||||
t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
|
t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
|
||||||
}
|
}
|
||||||
#elif defined(PCF8563_RTC)
|
#elif defined(PCF8563_RTC)
|
||||||
if (rtc_found == PCF8563_RTC) {
|
if (rtc_found.address == PCF8563_RTC) {
|
||||||
PCF8563_Class rtc;
|
PCF8563_Class rtc;
|
||||||
#ifdef RTC_USE_WIRE1
|
|
||||||
rtc.begin(Wire1);
|
#ifdef I2C_SDA1
|
||||||
|
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
|
||||||
#else
|
#else
|
||||||
rtc.begin();
|
rtc.begin();
|
||||||
#endif
|
#endif
|
||||||
@@ -139,6 +163,13 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the RTC time if the provided time is of higher quality than the current RTC time.
|
||||||
|
*
|
||||||
|
* @param q The quality of the provided time.
|
||||||
|
* @param t The time to potentially set the RTC to.
|
||||||
|
* @return True if the RTC was set to the provided time, false otherwise.
|
||||||
|
*/
|
||||||
bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||||
{
|
{
|
||||||
/* Convert to unix time
|
/* Convert to unix time
|
||||||
@@ -159,11 +190,22 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current time in seconds since the Unix epoch (January 1, 1970).
|
||||||
|
*
|
||||||
|
* @return The current time in seconds since the Unix epoch.
|
||||||
|
*/
|
||||||
uint32_t getTime()
|
uint32_t getTime()
|
||||||
{
|
{
|
||||||
return (((uint32_t)millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
|
return (((uint32_t)millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current time from the RTC if the quality of the time is at least minQuality.
|
||||||
|
*
|
||||||
|
* @param minQuality The minimum quality of the RTC time required for it to be considered valid.
|
||||||
|
* @return The current time from the RTC if it meets the minimum quality requirement, or 0 if the time is not valid.
|
||||||
|
*/
|
||||||
uint32_t getValidTime(RTCQuality minQuality)
|
uint32_t getValidTime(RTCQuality minQuality)
|
||||||
{
|
{
|
||||||
return (currentQuality >= minQuality) ? getTime() : 0;
|
return (currentQuality >= minQuality) ? getTime() : 0;
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
|
||||||
|
// #ifdef HELTEC_WIRELESS_PAPER
|
||||||
|
// SPIClass *hspi = NULL;
|
||||||
|
// #endif
|
||||||
|
|
||||||
#define COLORED GxEPD_BLACK
|
#define COLORED GxEPD_BLACK
|
||||||
#define UNCOLORED GxEPD_WHITE
|
#define UNCOLORED GxEPD_WHITE
|
||||||
|
|
||||||
@@ -19,13 +23,17 @@
|
|||||||
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
|
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
|
||||||
|
|
||||||
// 4.2 inch 300x400 - GxEPD2_420_M01
|
// 4.2 inch 300x400 - GxEPD2_420_M01
|
||||||
//#define TECHO_DISPLAY_MODEL GxEPD2_420_M01
|
// #define TECHO_DISPLAY_MODEL GxEPD2_420_M01
|
||||||
|
|
||||||
// 2.9 inch 296x128 - GxEPD2_290_T5D
|
// 2.9 inch 296x128 - GxEPD2_290_T5D
|
||||||
//#define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
|
// #define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
|
||||||
|
|
||||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||||
//#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
// #define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
||||||
|
|
||||||
|
#elif defined(MAKERPYTHON)
|
||||||
|
// 2.9 inch 296x128 - GxEPD2_290_T5D
|
||||||
|
#define TECHO_DISPLAY_MODEL GxEPD2_290_T5D
|
||||||
|
|
||||||
#elif defined(PCA10059)
|
#elif defined(PCA10059)
|
||||||
|
|
||||||
@@ -37,11 +45,14 @@
|
|||||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||||
#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
||||||
|
|
||||||
|
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||||
|
//#define TECHO_DISPLAY_MODEL GxEPD2_213_T5D
|
||||||
|
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
|
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
|
||||||
|
|
||||||
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model)
|
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||||
{
|
{
|
||||||
#if defined(TTGO_T_ECHO)
|
#if defined(TTGO_T_ECHO)
|
||||||
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
|
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
|
||||||
@@ -59,6 +70,13 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model
|
|||||||
// GxEPD2_154_M09
|
// GxEPD2_154_M09
|
||||||
// setGeometry(GEOMETRY_RAWMODE, 200, 200);
|
// setGeometry(GEOMETRY_RAWMODE, 200, 200);
|
||||||
|
|
||||||
|
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||||
|
// setGeometry(GEOMETRY_RAWMODE, 212, 104);
|
||||||
|
setGeometry(GEOMETRY_RAWMODE, 250, 122);
|
||||||
|
#elif defined(MAKERPYTHON)
|
||||||
|
// GxEPD2_290_T5D
|
||||||
|
setGeometry(GEOMETRY_RAWMODE, 296, 128);
|
||||||
|
|
||||||
#elif defined(PCA10059)
|
#elif defined(PCA10059)
|
||||||
|
|
||||||
// GxEPD2_420_M01
|
// GxEPD2_420_M01
|
||||||
@@ -69,6 +87,11 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model
|
|||||||
// M5Stack_CoreInk 200x200
|
// M5Stack_CoreInk 200x200
|
||||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||||
setGeometry(GEOMETRY_RAWMODE, EPD_HEIGHT, EPD_WIDTH);
|
setGeometry(GEOMETRY_RAWMODE, EPD_HEIGHT, EPD_WIDTH);
|
||||||
|
#elif defined(my)
|
||||||
|
|
||||||
|
// GxEPD2_290_T5D
|
||||||
|
setGeometry(GEOMETRY_RAWMODE, 296, 128);
|
||||||
|
LOG_DEBUG("GEOMETRY_RAWMODE, 296, 128\n");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
||||||
@@ -97,7 +120,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
|||||||
for (uint32_t y = 0; y < displayHeight; y++) {
|
for (uint32_t y = 0; y < displayHeight; y++) {
|
||||||
for (uint32_t x = 0; x < displayWidth; x++) {
|
for (uint32_t x = 0; x < displayWidth; x++) {
|
||||||
|
|
||||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient
|
||||||
auto b = buffer[x + (y / 8) * displayWidth];
|
auto b = buffer[x + (y / 8) * displayWidth];
|
||||||
auto isset = b & (1 << (y & 7));
|
auto isset = b & (1 << (y & 7));
|
||||||
adafruitDisplay->drawPixel(x, y, isset ? COLORED : UNCOLORED);
|
adafruitDisplay->drawPixel(x, y, isset ? COLORED : UNCOLORED);
|
||||||
@@ -109,7 +132,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
|||||||
#if defined(TTGO_T_ECHO)
|
#if defined(TTGO_T_ECHO)
|
||||||
// ePaper.Reset(); // wake the screen from sleep
|
// ePaper.Reset(); // wake the screen from sleep
|
||||||
adafruitDisplay->display(false); // FIXME, use partial update mode
|
adafruitDisplay->display(false); // FIXME, use partial update mode
|
||||||
#elif defined(RAK4630)
|
#elif defined(RAK4630) || defined(MAKERPYTHON)
|
||||||
|
|
||||||
// RAK14000 2.13 inch b/w 250x122 actually now does support partial updates
|
// RAK14000 2.13 inch b/w 250x122 actually now does support partial updates
|
||||||
|
|
||||||
@@ -125,6 +148,10 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
|||||||
|
|
||||||
#elif defined(PCA10059) || defined(M5_COREINK)
|
#elif defined(PCA10059) || defined(M5_COREINK)
|
||||||
adafruitDisplay->nextPage();
|
adafruitDisplay->nextPage();
|
||||||
|
|
||||||
|
#elif defined(PRIVATE_HW) || defined(my)
|
||||||
|
adafruitDisplay->nextPage();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
|
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
|
||||||
@@ -184,7 +211,7 @@ bool EInkDisplay::connect()
|
|||||||
adafruitDisplay->init();
|
adafruitDisplay->init();
|
||||||
adafruitDisplay->setRotation(3);
|
adafruitDisplay->setRotation(3);
|
||||||
}
|
}
|
||||||
#elif defined(RAK4630)
|
#elif defined(RAK4630) || defined(MAKERPYTHON)
|
||||||
{
|
{
|
||||||
if (eink_found) {
|
if (eink_found) {
|
||||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||||
@@ -202,6 +229,16 @@ bool EInkDisplay::connect()
|
|||||||
(void)adafruitDisplay;
|
(void)adafruitDisplay;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||||
|
{
|
||||||
|
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||||
|
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||||
|
// hspi = new SPIClass(HSPI);
|
||||||
|
// hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS
|
||||||
|
adafruitDisplay->init(115200, true, 10, false, SPI, SPISettings(6000000, MSBFIRST, SPI_MODE0));
|
||||||
|
adafruitDisplay->setRotation(3);
|
||||||
|
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||||
|
}
|
||||||
#elif defined(PCA10059)
|
#elif defined(PCA10059)
|
||||||
{
|
{
|
||||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||||
@@ -216,6 +253,14 @@ bool EInkDisplay::connect()
|
|||||||
adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||||
adafruitDisplay->setRotation(0);
|
adafruitDisplay->setRotation(0);
|
||||||
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
|
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
|
||||||
|
#elif defined(my)
|
||||||
|
{
|
||||||
|
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||||
|
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||||
|
adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||||
|
adafruitDisplay->setRotation(1);
|
||||||
|
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// adafruitDisplay->setFullWindow();
|
// adafruitDisplay->setFullWindow();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An adapter class that allows using the TFT_eSPI library as if it was an OLEDDisplay implementation.
|
* An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation.
|
||||||
*
|
*
|
||||||
* Remaining TODO:
|
* Remaining TODO:
|
||||||
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
||||||
@@ -22,7 +22,7 @@ class EInkDisplay : public OLEDDisplay
|
|||||||
/* constructor
|
/* constructor
|
||||||
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
|
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
|
||||||
*/
|
*/
|
||||||
EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model);
|
EInkDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
|
||||||
|
|
||||||
// Write the buffer to the display memory (for eink we only do this occasionally)
|
// Write the buffer to the display memory (for eink we only do this occasionally)
|
||||||
virtual void display(void) override;
|
virtual void display(void) override;
|
||||||
|
|||||||
7
src/graphics/RAKled.h
Normal file
7
src/graphics/RAKled.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#ifdef HAS_NCP5623
|
||||||
|
#include <NCP5623.h>
|
||||||
|
extern NCP5623 rgb;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
#include "Screen.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#if HAS_SCREEN
|
#if HAS_SCREEN
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
@@ -26,19 +27,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "Screen.h"
|
#include "error.h"
|
||||||
#include "gps/GeoCoord.h"
|
#include "gps/GeoCoord.h"
|
||||||
#include "gps/RTC.h"
|
#include "gps/RTC.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
|
#include "input/TouchScreenImpl1.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "mesh/Channels.h"
|
#include "mesh/Channels.h"
|
||||||
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
||||||
|
#include "meshUtils.h"
|
||||||
#include "modules/ExternalNotificationModule.h"
|
#include "modules/ExternalNotificationModule.h"
|
||||||
#include "modules/TextMessageModule.h"
|
#include "modules/TextMessageModule.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
#include "esp_task_wdt.h"
|
#include "esp_task_wdt.h"
|
||||||
@@ -50,6 +52,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "fonts/OLEDDisplayFontsRU.h"
|
#include "fonts/OLEDDisplayFontsRU.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef OLED_UA
|
||||||
|
#include "fonts/OLEDDisplayFontsUA.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace meshtastic; /** @todo remove */
|
using namespace meshtastic; /** @todo remove */
|
||||||
|
|
||||||
namespace graphics
|
namespace graphics
|
||||||
@@ -70,6 +76,8 @@ static char btPIN[16] = "888888";
|
|||||||
|
|
||||||
uint32_t logo_timeout = 5000; // 4 seconds for EACH logo
|
uint32_t logo_timeout = 5000; // 4 seconds for EACH logo
|
||||||
|
|
||||||
|
uint32_t hours_in_month = 730;
|
||||||
|
|
||||||
// This image definition is here instead of images.h because it's modified dynamically by the drawBattery function
|
// This image definition is here instead of images.h because it's modified dynamically by the drawBattery function
|
||||||
uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C};
|
uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C};
|
||||||
|
|
||||||
@@ -95,7 +103,8 @@ static uint16_t displayWidth, displayHeight;
|
|||||||
#define SCREEN_WIDTH displayWidth
|
#define SCREEN_WIDTH displayWidth
|
||||||
#define SCREEN_HEIGHT displayHeight
|
#define SCREEN_HEIGHT displayHeight
|
||||||
|
|
||||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||||
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
// The screen is bigger so use bigger fonts
|
// The screen is bigger so use bigger fonts
|
||||||
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
|
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
|
||||||
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
|
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
|
||||||
@@ -104,8 +113,12 @@ static uint16_t displayWidth, displayHeight;
|
|||||||
#ifdef OLED_RU
|
#ifdef OLED_RU
|
||||||
#define FONT_SMALL ArialMT_Plain_10_RU
|
#define FONT_SMALL ArialMT_Plain_10_RU
|
||||||
#else
|
#else
|
||||||
|
#ifdef OLED_UA
|
||||||
|
#define FONT_SMALL ArialMT_Plain_10_UA
|
||||||
|
#else
|
||||||
#define FONT_SMALL ArialMT_Plain_10 // Height: 13
|
#define FONT_SMALL ArialMT_Plain_10 // Height: 13
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
#define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
|
#define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
|
||||||
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
||||||
#endif
|
#endif
|
||||||
@@ -285,7 +298,7 @@ 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 x_offset = display->width() / 2;
|
||||||
int y_offset = display->height() == 64 ? 0 : 32;
|
int y_offset = display->height() <= 80 ? 0 : 32;
|
||||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
display->setFont(FONT_MEDIUM);
|
display->setFont(FONT_MEDIUM);
|
||||||
display->drawString(x_offset + x, y_offset + y, "Bluetooth");
|
display->drawString(x_offset + x, y_offset + y, "Bluetooth");
|
||||||
@@ -309,18 +322,18 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
|
|||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
uint16_t x_offset = display->width() / 2;
|
||||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
|
|
||||||
display->setFont(FONT_MEDIUM);
|
display->setFont(FONT_MEDIUM);
|
||||||
display->drawString(64 + x, 26 + y, "Shutting down...");
|
display->drawString(x_offset + x, 26 + y, "Shutting down...");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawFrameReboot(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawFrameReboot(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
|
uint16_t x_offset = display->width() / 2;
|
||||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
|
|
||||||
display->setFont(FONT_MEDIUM);
|
display->setFont(FONT_MEDIUM);
|
||||||
display->drawString(64 + x, 26 + y, "Rebooting...");
|
display->drawString(x_offset + x, 26 + y, "Rebooting...");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
@@ -338,35 +351,31 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
|||||||
/// Draw the last text message we received
|
/// Draw the last text message we received
|
||||||
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
displayedNodeNum = 0; // Not currently showing a node pane
|
|
||||||
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
display->setFont(FONT_MEDIUM);
|
display->setFont(FONT_MEDIUM);
|
||||||
|
|
||||||
char tempBuf[24];
|
char tempBuf[24];
|
||||||
snprintf(tempBuf, sizeof(tempBuf), "Critical fault #%d", myNodeInfo.error_code);
|
snprintf(tempBuf, sizeof(tempBuf), "Critical fault #%d", error_code);
|
||||||
display->drawString(0 + x, 0 + y, tempBuf);
|
display->drawString(0 + x, 0 + y, tempBuf);
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org");
|
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
||||||
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
|
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
|
||||||
{
|
{
|
||||||
return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled;
|
return packet->from != 0 && !moduleConfig.store_forward.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the last text message we received
|
/// Draw the last text message we received
|
||||||
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
displayedNodeNum = 0; // Not currently showing a node pane
|
|
||||||
|
|
||||||
// the max length of this buffer is much longer than we can possibly print
|
// the max length of this buffer is much longer than we can possibly print
|
||||||
static char tempBuf[237];
|
static char tempBuf[237];
|
||||||
|
|
||||||
meshtastic_MeshPacket &mp = devicestate.rx_text_message;
|
const meshtastic_MeshPacket &mp = devicestate.rx_text_message;
|
||||||
meshtastic_NodeInfo *node = nodeDB.getNode(getFrom(&mp));
|
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
|
||||||
// LOG_DEBUG("drawing text message from 0x%x: %s\n", mp.from,
|
// LOG_DEBUG("drawing text message from 0x%x: %s\n", mp.from,
|
||||||
// mp.decoded.variant.data.decoded.bytes);
|
// mp.decoded.variant.data.decoded.bytes);
|
||||||
|
|
||||||
@@ -379,16 +388,63 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
|||||||
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(0 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
|
|
||||||
|
uint32_t seconds = sinceReceived(&mp);
|
||||||
|
uint32_t minutes = seconds / 60;
|
||||||
|
uint32_t hours = minutes / 60;
|
||||||
|
uint32_t days = hours / 24;
|
||||||
|
|
||||||
if (config.display.heading_bold) {
|
if (config.display.heading_bold) {
|
||||||
display->drawStringf(1 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
|
display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s",
|
||||||
|
screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||||
|
(node && node->has_user) ? node->user.short_name : "???");
|
||||||
}
|
}
|
||||||
|
display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||||
|
(node && node->has_user) ? node->user.short_name : "???");
|
||||||
|
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
|
snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
|
||||||
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
|
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw a series of fields in a column, wrapping to multiple colums if needed
|
/// Draw the last waypoint we received
|
||||||
|
static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
|
{
|
||||||
|
static char tempBuf[237];
|
||||||
|
|
||||||
|
meshtastic_MeshPacket &mp = devicestate.rx_waypoint;
|
||||||
|
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(getFrom(&mp));
|
||||||
|
|
||||||
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
|
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||||
|
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||||
|
display->setColor(BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t seconds = sinceReceived(&mp);
|
||||||
|
uint32_t minutes = seconds / 60;
|
||||||
|
uint32_t hours = minutes / 60;
|
||||||
|
uint32_t days = hours / 24;
|
||||||
|
|
||||||
|
if (config.display.heading_bold) {
|
||||||
|
display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s",
|
||||||
|
screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||||
|
(node && node->has_user) ? node->user.short_name : "???");
|
||||||
|
}
|
||||||
|
display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||||
|
(node && node->has_user) ? node->user.short_name : "???");
|
||||||
|
|
||||||
|
display->setColor(WHITE);
|
||||||
|
meshtastic_Waypoint scratch;
|
||||||
|
memset(&scratch, 0, sizeof(scratch));
|
||||||
|
if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
|
||||||
|
snprintf(tempBuf, sizeof(tempBuf), "Received waypoint: %s", scratch.name);
|
||||||
|
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a series of fields in a column, wrapping to multiple columns if needed
|
||||||
static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
|
static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
|
||||||
{
|
{
|
||||||
// The coordinates define the left starting point of the text
|
// The coordinates define the left starting point of the text
|
||||||
@@ -411,38 +467,6 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/// Draw a series of fields in a row, wrapping to multiple rows if needed
|
|
||||||
/// @return the max y we ended up printing to
|
|
||||||
static uint32_t drawRows(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
|
|
||||||
{
|
|
||||||
// The coordinates define the left starting point of the text
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
|
||||||
|
|
||||||
const char **f = fields;
|
|
||||||
int xo = x, yo = y;
|
|
||||||
const int COLUMNS = 2; // hardwired for two columns per row....
|
|
||||||
int col = 0; // track which column we are on
|
|
||||||
while (*f) {
|
|
||||||
display->drawString(xo, yo, *f);
|
|
||||||
xo += SCREEN_WIDTH / COLUMNS;
|
|
||||||
// Wrap to next row, if needed.
|
|
||||||
if (++col >= COLUMNS) {
|
|
||||||
xo = x;
|
|
||||||
yo += FONT_HEIGHT_SMALL;
|
|
||||||
col = 0;
|
|
||||||
}
|
|
||||||
f++;
|
|
||||||
}
|
|
||||||
if (col != 0) {
|
|
||||||
// Include last incomplete line in our total.
|
|
||||||
yo += FONT_HEIGHT_SMALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return yo;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage.
|
// Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage.
|
||||||
static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus)
|
static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus)
|
||||||
{
|
{
|
||||||
@@ -466,11 +490,12 @@ static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *img
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw nodes status
|
// Draw nodes status
|
||||||
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *nodeStatus)
|
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const NodeStatus *nodeStatus)
|
||||||
{
|
{
|
||||||
char usersString[20];
|
char usersString[20];
|
||||||
snprintf(usersString, sizeof(usersString), "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
|
snprintf(usersString, sizeof(usersString), "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
|
||||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||||
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x, y + 3, 8, 8, imgUser);
|
display->drawFastImage(x, y + 3, 8, 8, imgUser);
|
||||||
#else
|
#else
|
||||||
display->drawFastImage(x, y, 8, 8, imgUser);
|
display->drawFastImage(x, y, 8, 8, imgUser);
|
||||||
@@ -530,18 +555,12 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
|
|||||||
// Draw status when gps is disabled by PMU
|
// Draw status when gps is disabled by PMU
|
||||||
static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||||
{
|
{
|
||||||
#ifdef HAS_PMU
|
|
||||||
String displayLine = "GPS disabled";
|
String displayLine = "GPS disabled";
|
||||||
int16_t xPos = display->getStringWidth(displayLine);
|
int16_t xPos = display->getStringWidth(displayLine);
|
||||||
|
|
||||||
if (!config.position.gps_enabled) {
|
if (!config.position.gps_enabled) {
|
||||||
display->drawString(x + xPos, y, displayLine);
|
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)
|
||||||
@@ -610,7 +629,6 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
|
|||||||
} else {
|
} else {
|
||||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine);
|
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
char latLine[22];
|
char latLine[22];
|
||||||
char lonLine[22];
|
char lonLine[22];
|
||||||
@@ -697,13 +715,6 @@ static float estimatedHeading(double lat, double lon)
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sometimes we will have Position objects that only have a time, so check for
|
|
||||||
/// valid lat/lon
|
|
||||||
static bool hasPosition(meshtastic_NodeInfo *n)
|
|
||||||
{
|
|
||||||
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t getCompassDiam(OLEDDisplay *display)
|
static uint16_t getCompassDiam(OLEDDisplay *display)
|
||||||
{
|
{
|
||||||
uint16_t diam = 0;
|
uint16_t diam = 0;
|
||||||
@@ -785,17 +796,16 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
if (state->currentFrame != prevFrame) {
|
if (state->currentFrame != prevFrame) {
|
||||||
prevFrame = state->currentFrame;
|
prevFrame = state->currentFrame;
|
||||||
|
|
||||||
nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes();
|
nodeIndex = (nodeIndex + 1) % nodeDB.getNumMeshNodes();
|
||||||
meshtastic_NodeInfo *n = nodeDB.getNodeByIndex(nodeIndex);
|
meshtastic_NodeInfoLite *n = nodeDB.getMeshNodeByIndex(nodeIndex);
|
||||||
if (n->num == nodeDB.getNodeNum()) {
|
if (n->num == nodeDB.getNodeNum()) {
|
||||||
// Don't show our node, just skip to next
|
// Don't show our node, just skip to next
|
||||||
nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes();
|
nodeIndex = (nodeIndex + 1) % nodeDB.getNumMeshNodes();
|
||||||
n = nodeDB.getNodeByIndex(nodeIndex);
|
n = nodeDB.getMeshNodeByIndex(nodeIndex);
|
||||||
}
|
}
|
||||||
displayedNodeNum = n->num;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
meshtastic_NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex);
|
meshtastic_NodeInfoLite *node = nodeDB.getMeshNodeByIndex(nodeIndex);
|
||||||
|
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
|
|
||||||
@@ -818,9 +828,6 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
else if (agoSecs < 120 * 60) // last 2 hrs
|
else if (agoSecs < 120 * 60) // last 2 hrs
|
||||||
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
|
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
|
||||||
else {
|
else {
|
||||||
|
|
||||||
uint32_t hours_in_month = 730;
|
|
||||||
|
|
||||||
// Only show hours ago if it's been less than 6 months. Otherwise, we may have bad
|
// Only show hours ago if it's been less than 6 months. Otherwise, we may have bad
|
||||||
// data.
|
// data.
|
||||||
if ((agoSecs / 60 / 60) < (hours_in_month * 6)) {
|
if ((agoSecs / 60 / 60) < (hours_in_month * 6)) {
|
||||||
@@ -831,8 +838,12 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char distStr[20];
|
static char distStr[20];
|
||||||
strncpy(distStr, "? km", sizeof(distStr)); // might not have location data
|
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||||
meshtastic_NodeInfo *ourNode = nodeDB.getNode(nodeDB.getNodeNum());
|
strncpy(distStr, "? mi", sizeof(distStr)); // might not have location data
|
||||||
|
} else {
|
||||||
|
strncpy(distStr, "? km", sizeof(distStr));
|
||||||
|
}
|
||||||
|
meshtastic_NodeInfoLite *ourNode = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||||
int16_t compassX = 0, compassY = 0;
|
int16_t compassX = 0, compassY = 0;
|
||||||
|
|
||||||
@@ -846,15 +857,15 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
}
|
}
|
||||||
bool hasNodeHeading = false;
|
bool hasNodeHeading = false;
|
||||||
|
|
||||||
if (ourNode && hasPosition(ourNode)) {
|
if (ourNode && hasValidPosition(ourNode)) {
|
||||||
meshtastic_Position &op = ourNode->position;
|
const meshtastic_PositionLite &op = ourNode->position;
|
||||||
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||||
drawCompassNorth(display, compassX, compassY, myHeading);
|
drawCompassNorth(display, compassX, compassY, myHeading);
|
||||||
|
|
||||||
if (hasPosition(node)) {
|
if (hasValidPosition(node)) {
|
||||||
// display direction toward node
|
// display direction toward node
|
||||||
hasNodeHeading = true;
|
hasNodeHeading = true;
|
||||||
meshtastic_Position &p = node->position;
|
const meshtastic_PositionLite &p = node->position;
|
||||||
float d =
|
float d =
|
||||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||||
|
|
||||||
@@ -882,7 +893,8 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
if (!hasNodeHeading) {
|
if (!hasNodeHeading) {
|
||||||
// direction to node is unknown so display question mark
|
// direction to node is unknown so display question mark
|
||||||
// Debug info for gps lock errors
|
// Debug info for gps lock errors
|
||||||
// LOG_DEBUG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
|
// LOG_DEBUG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasValidPosition(ourNode),
|
||||||
|
// hasValidPosition(node));
|
||||||
display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
|
display->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);
|
||||||
@@ -908,13 +920,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// #else
|
// #else
|
||||||
Screen::Screen(uint8_t address, int sda, int scl)
|
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
|
||||||
: OSThread("Screen"), cmdQueue(32),
|
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32),
|
||||||
dispdev(address, sda, scl,
|
dispdev(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE),
|
||||||
screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 ? GEOMETRY_128_128 : GEOMETRY_128_64),
|
|
||||||
ui(&dispdev)
|
ui(&dispdev)
|
||||||
{
|
{
|
||||||
address_found = address;
|
|
||||||
cmdQueue.setReader(this);
|
cmdQueue.setReader(this);
|
||||||
}
|
}
|
||||||
// #endif
|
// #endif
|
||||||
@@ -941,6 +951,9 @@ void Screen::handleSetOn(bool on)
|
|||||||
if (on != screenOn) {
|
if (on != screenOn) {
|
||||||
if (on) {
|
if (on) {
|
||||||
LOG_INFO("Turning on screen\n");
|
LOG_INFO("Turning on screen\n");
|
||||||
|
#ifdef T_WATCH_S3
|
||||||
|
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||||
|
#endif
|
||||||
dispdev.displayOn();
|
dispdev.displayOn();
|
||||||
dispdev.displayOn();
|
dispdev.displayOn();
|
||||||
enabled = true;
|
enabled = true;
|
||||||
@@ -949,6 +962,9 @@ void Screen::handleSetOn(bool on)
|
|||||||
} else {
|
} else {
|
||||||
LOG_INFO("Turning off screen\n");
|
LOG_INFO("Turning off screen\n");
|
||||||
dispdev.displayOff();
|
dispdev.displayOff();
|
||||||
|
#ifdef T_WATCH_S3
|
||||||
|
PMU->disablePowerOutput(XPOWERS_ALDO2);
|
||||||
|
#endif
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
screenOn = on;
|
screenOn = on;
|
||||||
@@ -962,9 +978,11 @@ void Screen::setup()
|
|||||||
useDisplay = true;
|
useDisplay = true;
|
||||||
|
|
||||||
#ifdef AutoOLEDWire_h
|
#ifdef AutoOLEDWire_h
|
||||||
if (screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107)
|
dispdev.setDetected(model);
|
||||||
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1106;
|
#endif
|
||||||
dispdev.setDetected(screen_model);
|
|
||||||
|
#ifdef USE_SH1107_128_64
|
||||||
|
dispdev.setSubtype(7);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Initialising the UI will init the display too.
|
// Initialising the UI will init the display too.
|
||||||
@@ -1029,12 +1047,19 @@ void Screen::setup()
|
|||||||
#endif
|
#endif
|
||||||
serialSinceMsec = millis();
|
serialSinceMsec = millis();
|
||||||
|
|
||||||
|
#if HAS_TOUCHSCREEN
|
||||||
|
touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch);
|
||||||
|
touchScreenImpl1->init();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Subscribe to status updates
|
// Subscribe to status updates
|
||||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||||
if (textMessageModule)
|
if (textMessageModule)
|
||||||
textMessageObserver.observe(textMessageModule);
|
textMessageObserver.observe(textMessageModule);
|
||||||
|
if (inputBroker)
|
||||||
|
inputObserver.observe(inputBroker);
|
||||||
|
|
||||||
// Modules can notify screen about refresh
|
// Modules can notify screen about refresh
|
||||||
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
||||||
@@ -1112,6 +1137,12 @@ int32_t Screen::runOnce()
|
|||||||
handleOnPress();
|
handleOnPress();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Cmd::SHOW_PREV_FRAME:
|
||||||
|
handleShowPrevFrame();
|
||||||
|
break;
|
||||||
|
case Cmd::SHOW_NEXT_FRAME:
|
||||||
|
handleShowNextFrame();
|
||||||
|
break;
|
||||||
case Cmd::START_BLUETOOTH_PIN_SCREEN:
|
case Cmd::START_BLUETOOTH_PIN_SCREEN:
|
||||||
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
|
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
|
||||||
break;
|
break;
|
||||||
@@ -1199,7 +1230,7 @@ void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiStat
|
|||||||
* it is expected that this will be used during the boot phase */
|
* it is expected that this will be used during the boot phase */
|
||||||
void Screen::setSSLFrames()
|
void Screen::setSSLFrames()
|
||||||
{
|
{
|
||||||
if (address_found) {
|
if (address_found.address) {
|
||||||
// LOG_DEBUG("showing SSL frames\n");
|
// LOG_DEBUG("showing SSL frames\n");
|
||||||
static FrameCallback sslFrames[] = {drawSSLScreen};
|
static FrameCallback sslFrames[] = {drawSSLScreen};
|
||||||
ui.setFrames(sslFrames, 1);
|
ui.setFrames(sslFrames, 1);
|
||||||
@@ -1211,7 +1242,7 @@ void Screen::setSSLFrames()
|
|||||||
* it is expected that this will be used during the boot phase */
|
* it is expected that this will be used during the boot phase */
|
||||||
void Screen::setWelcomeFrames()
|
void Screen::setWelcomeFrames()
|
||||||
{
|
{
|
||||||
if (address_found) {
|
if (address_found.address) {
|
||||||
// LOG_DEBUG("showing Welcome frames\n");
|
// LOG_DEBUG("showing Welcome frames\n");
|
||||||
ui.disableAllIndicators();
|
ui.disableAllIndicators();
|
||||||
|
|
||||||
@@ -1229,13 +1260,15 @@ void Screen::setFrames()
|
|||||||
|
|
||||||
moduleFrames = MeshModule::GetMeshModulesWithUIFrames();
|
moduleFrames = MeshModule::GetMeshModulesWithUIFrames();
|
||||||
LOG_DEBUG("Showing %d module frames\n", moduleFrames.size());
|
LOG_DEBUG("Showing %d module frames\n", moduleFrames.size());
|
||||||
|
#ifdef DEBUG_PORT
|
||||||
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.size();
|
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.size();
|
||||||
LOG_DEBUG("Total frame count: %d\n", totalFrameCount);
|
LOG_DEBUG("Total frame count: %d\n", totalFrameCount);
|
||||||
|
#endif
|
||||||
|
|
||||||
// We don't show the node info our our node (if we have it yet - we should)
|
// We don't show the node info our our node (if we have it yet - we should)
|
||||||
size_t numnodes = nodeStatus->getNumTotal();
|
size_t numMeshNodes = nodeDB.getNumMeshNodes();
|
||||||
if (numnodes > 0)
|
if (numMeshNodes > 0)
|
||||||
numnodes--;
|
numMeshNodes--;
|
||||||
|
|
||||||
size_t numframes = 0;
|
size_t numframes = 0;
|
||||||
|
|
||||||
@@ -1252,17 +1285,21 @@ void Screen::setFrames()
|
|||||||
LOG_DEBUG("Added modules. numframes: %d\n", numframes);
|
LOG_DEBUG("Added modules. numframes: %d\n", numframes);
|
||||||
|
|
||||||
// If we have a critical fault, show it first
|
// If we have a critical fault, show it first
|
||||||
if (myNodeInfo.error_code)
|
if (error_code)
|
||||||
normalFrames[numframes++] = drawCriticalFaultFrame;
|
normalFrames[numframes++] = drawCriticalFaultFrame;
|
||||||
|
|
||||||
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
|
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
|
||||||
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
|
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
|
||||||
normalFrames[numframes++] = drawTextMessageFrame;
|
normalFrames[numframes++] = drawTextMessageFrame;
|
||||||
}
|
}
|
||||||
|
// If we have a waypoint - show it next, unless it's a phone message and we aren't using any special modules
|
||||||
|
if (devicestate.has_rx_waypoint && shouldDrawMessage(&devicestate.rx_waypoint)) {
|
||||||
|
normalFrames[numframes++] = drawWaypointFrame;
|
||||||
|
}
|
||||||
|
|
||||||
// then all the nodes
|
// then all the nodes
|
||||||
// We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens
|
// We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens
|
||||||
size_t numToShow = min(numnodes, 4U);
|
size_t numToShow = min(numMeshNodes, 4U);
|
||||||
for (size_t i = 0; i < numToShow; i++)
|
for (size_t i = 0; i < numToShow; i++)
|
||||||
normalFrames[numframes++] = drawNodeInfo;
|
normalFrames[numframes++] = drawNodeInfo;
|
||||||
|
|
||||||
@@ -1360,6 +1397,23 @@ void Screen::blink()
|
|||||||
dispdev.setBrightness(brightness);
|
dispdev.setBrightness(brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds)
|
||||||
|
{
|
||||||
|
std::string uptime;
|
||||||
|
|
||||||
|
if (days > (hours_in_month * 6))
|
||||||
|
uptime = "?";
|
||||||
|
else if (days >= 2)
|
||||||
|
uptime = std::to_string(days) + "d";
|
||||||
|
else if (hours >= 2)
|
||||||
|
uptime = std::to_string(hours) + "h";
|
||||||
|
else if (minutes >= 1)
|
||||||
|
uptime = std::to_string(minutes) + "m";
|
||||||
|
else
|
||||||
|
uptime = std::to_string(seconds) + "s";
|
||||||
|
return uptime;
|
||||||
|
}
|
||||||
|
|
||||||
void Screen::handlePrint(const char *text)
|
void Screen::handlePrint(const char *text)
|
||||||
{
|
{
|
||||||
// the string passed into us probably has a newline, but that would confuse the logging system
|
// the string passed into us probably has a newline, but that would confuse the logging system
|
||||||
@@ -1382,6 +1436,28 @@ void Screen::handleOnPress()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Screen::handleShowPrevFrame()
|
||||||
|
{
|
||||||
|
// If screen was off, just wake it, otherwise go back to previous frame
|
||||||
|
// If we are in a transition, the press must have bounced, drop it.
|
||||||
|
if (ui.getUiState()->frameState == FIXED) {
|
||||||
|
ui.previousFrame();
|
||||||
|
lastScreenTransition = millis();
|
||||||
|
setFastFramerate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::handleShowNextFrame()
|
||||||
|
{
|
||||||
|
// If screen was off, just wake it, otherwise advance to next frame
|
||||||
|
// If we are in a transition, the press must have bounced, drop it.
|
||||||
|
if (ui.getUiState()->frameState == FIXED) {
|
||||||
|
ui.nextFrame();
|
||||||
|
lastScreenTransition = millis();
|
||||||
|
setFastFramerate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SCREEN_TRANSITION_FRAMERATE
|
#ifndef SCREEN_TRANSITION_FRAMERATE
|
||||||
#define SCREEN_TRANSITION_FRAMERATE 30 // fps
|
#define SCREEN_TRANSITION_FRAMERATE 30 // fps
|
||||||
#endif
|
#endif
|
||||||
@@ -1398,8 +1474,6 @@ void Screen::setFastFramerate()
|
|||||||
|
|
||||||
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
displayedNodeNum = 0; // Not currently showing a node pane
|
|
||||||
|
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
|
|
||||||
// The coordinates define the left starting point of the text
|
// The coordinates define the left starting point of the text
|
||||||
@@ -1439,11 +1513,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
}
|
}
|
||||||
// Display GPS status
|
// Display GPS status
|
||||||
if (!config.position.gps_enabled) {
|
if (!config.position.gps_enabled) {
|
||||||
int16_t yPos = y + 2;
|
drawGPSpowerstat(display, x, y + 2, gpsStatus);
|
||||||
#ifdef GPS_POWER_TOGGLE
|
|
||||||
yPos = (y + 10 + FONT_HEIGHT_SMALL);
|
|
||||||
#endif
|
|
||||||
drawGPSpowerstat(display, x, yPos, gpsStatus);
|
|
||||||
} else {
|
} else {
|
||||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
|
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||||||
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
|
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
|
||||||
@@ -1460,7 +1530,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
if (millis() - storeForwardModule->lastHeartbeat >
|
if (millis() - storeForwardModule->lastHeartbeat >
|
||||||
(storeForwardModule->heartbeatInterval * 1200)) { // no heartbeat, overlap a bit
|
(storeForwardModule->heartbeatInterval * 1200)) { // no heartbeat, overlap a bit
|
||||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||||
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||||
imgQuestionL1);
|
imgQuestionL1);
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||||||
@@ -1470,7 +1541,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
imgQuestion);
|
imgQuestion);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||||
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8,
|
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8,
|
||||||
imgSFL1);
|
imgSFL1);
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8,
|
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8,
|
||||||
@@ -1482,7 +1554,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||||
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||||
imgInfoL1);
|
imgInfoL1);
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||||||
@@ -1511,8 +1584,6 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
|||||||
#if HAS_WIFI
|
#if HAS_WIFI
|
||||||
const char *wifiName = config.network.wifi_ssid;
|
const char *wifiName = config.network.wifi_ssid;
|
||||||
|
|
||||||
displayedNodeNum = 0; // Not currently showing a node pane
|
|
||||||
|
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
|
|
||||||
// The coordinates define the left starting point of the text
|
// The coordinates define the left starting point of the text
|
||||||
@@ -1643,8 +1714,6 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
|||||||
|
|
||||||
void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
displayedNodeNum = 0; // Not currently showing a node pane
|
|
||||||
|
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
|
|
||||||
// The coordinates define the left starting point of the text
|
// The coordinates define the left starting point of the text
|
||||||
@@ -1695,6 +1764,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
|||||||
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
|
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
|
||||||
mode = "LongF";
|
mode = "LongF";
|
||||||
break;
|
break;
|
||||||
|
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
|
||||||
|
mode = "LongM";
|
||||||
|
break;
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
|
case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
|
||||||
mode = "VeryL";
|
mode = "VeryL";
|
||||||
break;
|
break;
|
||||||
@@ -1721,15 +1793,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
|||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
|
|
||||||
// Show uptime as days, hours, minutes OR seconds
|
// Show uptime as days, hours, minutes OR seconds
|
||||||
String uptime;
|
std::string uptime = screen->drawTimeDelta(days, hours, minutes, seconds);
|
||||||
if (days >= 2)
|
|
||||||
uptime += String(days) + "d ";
|
|
||||||
else if (hours >= 2)
|
|
||||||
uptime += String(hours) + "h ";
|
|
||||||
else if (minutes >= 1)
|
|
||||||
uptime += String(minutes) + "m ";
|
|
||||||
else
|
|
||||||
uptime += String(seconds) + "s ";
|
|
||||||
|
|
||||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
|
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
|
||||||
if (rtc_sec > 0) {
|
if (rtc_sec > 0) {
|
||||||
@@ -1744,12 +1808,12 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
|||||||
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||||
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
||||||
|
|
||||||
char timebuf[9];
|
char timebuf[10];
|
||||||
snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d", hour, min, sec);
|
snprintf(timebuf, sizeof(timebuf), " %02d:%02d:%02d", hour, min, sec);
|
||||||
uptime += timebuf;
|
uptime += timebuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, uptime);
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, uptime.c_str());
|
||||||
|
|
||||||
// Display Channel Utilization
|
// Display Channel Utilization
|
||||||
char chUtil[13];
|
char chUtil[13];
|
||||||
@@ -1765,6 +1829,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
|||||||
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
|
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
|
||||||
} else {
|
} else {
|
||||||
drawGPSpowerstat(display, x - (SCREEN_WIDTH / 4), y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
drawGPSpowerstat(display, x - (SCREEN_WIDTH / 4), y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
||||||
|
#ifdef GPS_POWER_TOGGLE
|
||||||
|
display->drawString(x + 30, (y + FONT_HEIGHT_SMALL * 3), " by button");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
|
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
|
||||||
#ifdef SHOW_REDRAWS
|
#ifdef SHOW_REDRAWS
|
||||||
@@ -1773,7 +1840,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
|||||||
heartbeat = !heartbeat;
|
heartbeat = !heartbeat;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// adjust Brightness cycle trough 1 to 254 as long as attachDuringLongPress is true
|
// adjust Brightness cycle through 1 to 254 as long as attachDuringLongPress is true
|
||||||
void Screen::adjustBrightness()
|
void Screen::adjustBrightness()
|
||||||
{
|
{
|
||||||
if (!useDisplay)
|
if (!useDisplay)
|
||||||
@@ -1831,6 +1898,21 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace graphics
|
int Screen::handleInputEvent(const InputEvent *event)
|
||||||
|
{
|
||||||
|
if (showingNormalScreen && moduleFrames.size() == 0) {
|
||||||
|
// LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
|
||||||
|
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||||
|
showPrevFrame();
|
||||||
|
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||||
|
showNextFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // HAS_SCREEN
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace graphics
|
||||||
|
#else
|
||||||
|
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
|
||||||
|
#endif // HAS_SCREEN
|
||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include "detect/ScanI2C.h"
|
||||||
|
#include "mesh/generated/meshtastic/config.pb.h"
|
||||||
|
#include <OLEDDisplay.h>
|
||||||
|
|
||||||
#if !HAS_SCREEN
|
#if !HAS_SCREEN
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
namespace graphics
|
namespace graphics
|
||||||
@@ -10,7 +14,7 @@ namespace graphics
|
|||||||
class Screen
|
class Screen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Screen(char) {}
|
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||||
void onPress() {}
|
void onPress() {}
|
||||||
void setup() {}
|
void setup() {}
|
||||||
void setOn(bool) {}
|
void setOn(bool) {}
|
||||||
@@ -21,10 +25,10 @@ class Screen
|
|||||||
void startBluetoothPinScreen(uint32_t pin) {}
|
void startBluetoothPinScreen(uint32_t pin) {}
|
||||||
void stopBluetoothPinScreen() {}
|
void stopBluetoothPinScreen() {}
|
||||||
void startRebootScreen() {}
|
void startRebootScreen() {}
|
||||||
|
void startShutdownScreen() {}
|
||||||
void startFirmwareUpdateScreen() {}
|
void startFirmwareUpdateScreen() {}
|
||||||
};
|
};
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
@@ -34,7 +38,7 @@ class Screen
|
|||||||
|
|
||||||
#ifdef USE_ST7567
|
#ifdef USE_ST7567
|
||||||
#include <ST7567Wire.h>
|
#include <ST7567Wire.h>
|
||||||
#elif defined(USE_SH1106) || defined(USE_SH1107)
|
#elif defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||||
#include <SH1106Wire.h>
|
#include <SH1106Wire.h>
|
||||||
#elif defined(USE_SSD1306)
|
#elif defined(USE_SSD1306)
|
||||||
#include <SSD1306Wire.h>
|
#include <SSD1306Wire.h>
|
||||||
@@ -49,6 +53,7 @@ class Screen
|
|||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
#include "concurrency/LockGuard.h"
|
#include "concurrency/LockGuard.h"
|
||||||
#include "concurrency/OSThread.h"
|
#include "concurrency/OSThread.h"
|
||||||
|
#include "input/InputBroker.h"
|
||||||
#include "mesh/MeshModule.h"
|
#include "mesh/MeshModule.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -114,14 +119,18 @@ class Screen : public concurrency::OSThread
|
|||||||
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
|
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
|
||||||
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
|
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
|
||||||
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
|
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
|
||||||
|
CallbackObserver<Screen, const InputEvent *> inputObserver =
|
||||||
|
CallbackObserver<Screen, const InputEvent *>(this, &Screen::handleInputEvent);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Screen(uint8_t address, int sda = -1, int scl = -1);
|
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||||
|
|
||||||
Screen(const Screen &) = delete;
|
Screen(const Screen &) = delete;
|
||||||
Screen &operator=(const Screen &) = delete;
|
Screen &operator=(const Screen &) = delete;
|
||||||
|
|
||||||
uint8_t address_found;
|
ScanI2C::DeviceAddress address_found;
|
||||||
|
meshtastic_Config_DisplayConfig_OledType model;
|
||||||
|
OLEDDISPLAY_GEOMETRY geometry;
|
||||||
|
|
||||||
/// Initializes the UI, turns on the display, starts showing boot screen.
|
/// Initializes the UI, turns on the display, starts showing boot screen.
|
||||||
//
|
//
|
||||||
@@ -146,8 +155,10 @@ class Screen : public concurrency::OSThread
|
|||||||
|
|
||||||
void blink();
|
void blink();
|
||||||
|
|
||||||
/// Handles a button press.
|
/// Handle button press, trackball or swipe action)
|
||||||
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
|
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
|
||||||
|
void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); }
|
||||||
|
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
|
||||||
|
|
||||||
// Implementation to Adjust Brightness
|
// Implementation to Adjust Brightness
|
||||||
void adjustBrightness();
|
void adjustBrightness();
|
||||||
@@ -206,6 +217,9 @@ class Screen : public concurrency::OSThread
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// generates a very brief time delta display
|
||||||
|
std::string drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds);
|
||||||
|
|
||||||
/// Overrides the default utf8 character conversion, to replace empty space with question marks
|
/// Overrides the default utf8 character conversion, to replace empty space with question marks
|
||||||
static char customFontTableLookup(const uint8_t ch)
|
static char customFontTableLookup(const uint8_t ch)
|
||||||
{
|
{
|
||||||
@@ -237,6 +251,12 @@ class Screen : public concurrency::OSThread
|
|||||||
// library have empty chars for non-latin ASCII symbols
|
// library have empty chars for non-latin ASCII symbols
|
||||||
case 0xD0: {
|
case 0xD0: {
|
||||||
SKIPREST = false;
|
SKIPREST = false;
|
||||||
|
if (ch == 132)
|
||||||
|
return (uint8_t)(170); // Є
|
||||||
|
if (ch == 134)
|
||||||
|
return (uint8_t)(178); // І
|
||||||
|
if (ch == 135)
|
||||||
|
return (uint8_t)(175); // Ї
|
||||||
if (ch == 129)
|
if (ch == 129)
|
||||||
return (uint8_t)(168); // Ё
|
return (uint8_t)(168); // Ё
|
||||||
if (ch > 143 && ch < 192)
|
if (ch > 143 && ch < 192)
|
||||||
@@ -245,12 +265,26 @@ class Screen : public concurrency::OSThread
|
|||||||
}
|
}
|
||||||
case 0xD1: {
|
case 0xD1: {
|
||||||
SKIPREST = false;
|
SKIPREST = false;
|
||||||
|
if (ch == 148)
|
||||||
|
return (uint8_t)(186); // є
|
||||||
|
if (ch == 150)
|
||||||
|
return (uint8_t)(179); // і
|
||||||
|
if (ch == 151)
|
||||||
|
return (uint8_t)(191); // ї
|
||||||
if (ch == 145)
|
if (ch == 145)
|
||||||
return (uint8_t)(184); // ё
|
return (uint8_t)(184); // ё
|
||||||
if (ch > 127 && ch < 144)
|
if (ch > 127 && ch < 144)
|
||||||
return (uint8_t)(ch + 112);
|
return (uint8_t)(ch + 112);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 0xD2: {
|
||||||
|
SKIPREST = false;
|
||||||
|
if (ch == 144)
|
||||||
|
return (uint8_t)(165); // Ґ
|
||||||
|
if (ch == 145)
|
||||||
|
return (uint8_t)(180); // ґ
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want to strip out prefix chars for two-byte char formats
|
// We want to strip out prefix chars for two-byte char formats
|
||||||
@@ -272,9 +306,11 @@ class Screen : public concurrency::OSThread
|
|||||||
// Use this handle to set things like battery status, user count, GPS status, etc.
|
// Use this handle to set things like battery status, user count, GPS status, etc.
|
||||||
DebugInfo *debug_info() { return &debugInfo; }
|
DebugInfo *debug_info() { return &debugInfo; }
|
||||||
|
|
||||||
|
// Handle observer events
|
||||||
int handleStatusUpdate(const meshtastic::Status *arg);
|
int handleStatusUpdate(const meshtastic::Status *arg);
|
||||||
int handleTextMessage(const meshtastic_MeshPacket *arg);
|
int handleTextMessage(const meshtastic_MeshPacket *arg);
|
||||||
int handleUIFrameEvent(const UIFrameEvent *arg);
|
int handleUIFrameEvent(const UIFrameEvent *arg);
|
||||||
|
int handleInputEvent(const InputEvent *arg);
|
||||||
|
|
||||||
/// Used to force (super slow) eink displays to draw critical frames
|
/// Used to force (super slow) eink displays to draw critical frames
|
||||||
void forceDisplay();
|
void forceDisplay();
|
||||||
@@ -314,6 +350,8 @@ class Screen : public concurrency::OSThread
|
|||||||
// Implementations of various commands, called from doTask().
|
// Implementations of various commands, called from doTask().
|
||||||
void handleSetOn(bool on);
|
void handleSetOn(bool on);
|
||||||
void handleOnPress();
|
void handleOnPress();
|
||||||
|
void handleShowNextFrame();
|
||||||
|
void handleShowPrevFrame();
|
||||||
void handleStartBluetoothPinScreen(uint32_t pin);
|
void handleStartBluetoothPinScreen(uint32_t pin);
|
||||||
void handlePrint(const char *text);
|
void handlePrint(const char *text);
|
||||||
void handleStartFirmwareUpdateScreen();
|
void handleStartFirmwareUpdateScreen();
|
||||||
@@ -347,11 +385,11 @@ class Screen : public concurrency::OSThread
|
|||||||
|
|
||||||
/// Display device
|
/// Display device
|
||||||
|
|
||||||
#if defined(USE_SH1106) || defined(USE_SH1107)
|
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||||
SH1106Wire dispdev;
|
SH1106Wire dispdev;
|
||||||
#elif defined(USE_SSD1306)
|
#elif defined(USE_SSD1306)
|
||||||
SSD1306Wire dispdev;
|
SSD1306Wire dispdev;
|
||||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
|
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||||
TFTDisplay dispdev;
|
TFTDisplay dispdev;
|
||||||
#elif defined(USE_EINK)
|
#elif defined(USE_EINK)
|
||||||
EInkDisplay dispdev;
|
EInkDisplay dispdev;
|
||||||
@@ -365,4 +403,4 @@ class Screen : public concurrency::OSThread
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
#endif
|
#endif
|
||||||
@@ -1,14 +1,329 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#if defined(ST7735_CS) || defined(ILI9341_DRIVER)
|
#ifndef TFT_BACKLIGHT_ON
|
||||||
#include "SPILock.h"
|
#define TFT_BACKLIGHT_ON HIGH
|
||||||
#include "TFTDisplay.h"
|
#endif
|
||||||
#include <SPI.h>
|
|
||||||
#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
|
#ifndef TFT_MESH
|
||||||
|
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ST7735S)
|
||||||
|
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||||
|
|
||||||
|
#if defined(ST7735_BACKLIGHT_EN) && !defined(TFT_BL)
|
||||||
|
#define TFT_BL ST7735_BACKLIGHT_EN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class LGFX : public lgfx::LGFX_Device
|
||||||
|
{
|
||||||
|
lgfx::Panel_ST7735S _panel_instance;
|
||||||
|
lgfx::Bus_SPI _bus_instance;
|
||||||
|
lgfx::Light_PWM _light_instance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LGFX(void)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto cfg = _bus_instance.config();
|
||||||
|
|
||||||
|
// configure SPI
|
||||||
|
cfg.spi_host = ST7735_SPI_HOST; // ESP32-S2,S3,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
|
||||||
|
cfg.spi_mode = 0;
|
||||||
|
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||||
|
// 80MHz by an integer)
|
||||||
|
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||||
|
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
|
||||||
|
cfg.use_lock = true; // Set to true to use transaction locking
|
||||||
|
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||||
|
// SPI_DMA_CH_AUTO=auto setting)
|
||||||
|
cfg.pin_sclk = ST7735_SCK; // Set SPI SCLK pin number
|
||||||
|
cfg.pin_mosi = ST7735_SDA; // Set SPI MOSI pin number
|
||||||
|
cfg.pin_miso = ST7735_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||||
|
cfg.pin_dc = ST7735_RS; // Set SPI DC pin number (-1 = disable)
|
||||||
|
|
||||||
|
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||||
|
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Set the display panel control.
|
||||||
|
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||||
|
|
||||||
|
cfg.pin_cs = ST7735_CS; // Pin number where CS is connected (-1 = disable)
|
||||||
|
cfg.pin_rst = ST7735_RESET; // Pin number where RST is connected (-1 = disable)
|
||||||
|
cfg.pin_busy = ST7735_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
||||||
|
|
||||||
|
// The following setting values are general initial values for each panel, so please comment out any
|
||||||
|
// unknown items and try them.
|
||||||
|
|
||||||
|
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||||
|
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||||
|
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||||
|
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||||
|
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is upside down)
|
||||||
|
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout
|
||||||
|
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||||
|
cfg.readable = true; // Set to true if data can be read
|
||||||
|
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||||
|
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||||
|
cfg.dlen_16bit =
|
||||||
|
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||||
|
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||||
|
|
||||||
|
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
|
||||||
|
// ST7735 or ILI9163.
|
||||||
|
cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||||
|
cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
||||||
|
_panel_instance.config(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the backlight control
|
||||||
|
{
|
||||||
|
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||||
|
|
||||||
|
cfg.pin_bl = ST7735_BL; // Pin number to which the backlight is connected
|
||||||
|
cfg.invert = true; // true to invert the brightness of the backlight
|
||||||
|
// cfg.freq = 44100; // PWM frequency of backlight
|
||||||
|
// cfg.pwm_channel = 1; // PWM channel number to use
|
||||||
|
|
||||||
|
_light_instance.config(cfg);
|
||||||
|
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||||
|
}
|
||||||
|
|
||||||
|
setPanel(&_panel_instance);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static LGFX tft;
|
||||||
|
|
||||||
|
#elif defined(ST7789_CS)
|
||||||
|
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||||
|
|
||||||
|
#if defined(ST7789_BACKLIGHT_EN) && !defined(TFT_BL)
|
||||||
|
#define TFT_BL ST7789_BACKLIGHT_EN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class LGFX : public lgfx::LGFX_Device
|
||||||
|
{
|
||||||
|
lgfx::Panel_ST7789 _panel_instance;
|
||||||
|
lgfx::Bus_SPI _bus_instance;
|
||||||
|
lgfx::Light_PWM _light_instance;
|
||||||
|
#if HAS_TOUCHSCREEN
|
||||||
|
#ifdef T_WATCH_S3
|
||||||
|
lgfx::Touch_FT5x06 _touch_instance;
|
||||||
|
#else
|
||||||
|
lgfx::Touch_GT911 _touch_instance;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
LGFX(void)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto cfg = _bus_instance.config();
|
||||||
|
|
||||||
|
// SPI
|
||||||
|
cfg.spi_host = ST7789_SPI_HOST;
|
||||||
|
cfg.spi_mode = 0;
|
||||||
|
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||||
|
// 80MHz by an integer)
|
||||||
|
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||||
|
cfg.spi_3wire = false;
|
||||||
|
cfg.use_lock = true; // Set to true to use transaction locking
|
||||||
|
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||||
|
// SPI_DMA_CH_AUTO=auto setting)
|
||||||
|
cfg.pin_sclk = ST7789_SCK; // Set SPI SCLK pin number
|
||||||
|
cfg.pin_mosi = ST7789_SDA; // Set SPI MOSI pin number
|
||||||
|
cfg.pin_miso = ST7789_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||||
|
cfg.pin_dc = ST7789_RS; // Set SPI DC pin number (-1 = disable)
|
||||||
|
|
||||||
|
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||||
|
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Set the display panel control.
|
||||||
|
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||||
|
|
||||||
|
cfg.pin_cs = ST7789_CS; // Pin number where CS is connected (-1 = disable)
|
||||||
|
cfg.pin_rst = -1; // Pin number where RST is connected (-1 = disable)
|
||||||
|
cfg.pin_busy = -1; // Pin number where BUSY is connected (-1 = disable)
|
||||||
|
|
||||||
|
// The following setting values are general initial values for each panel, so please comment out any
|
||||||
|
// unknown items and try them.
|
||||||
|
|
||||||
|
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||||
|
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||||
|
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||||
|
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||||
|
cfg.offset_rotation = TFT_OFFSET_ROTATION; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||||
|
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
|
||||||
|
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||||
|
cfg.readable = true; // Set to true if data can be read
|
||||||
|
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||||
|
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||||
|
cfg.dlen_16bit =
|
||||||
|
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||||
|
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||||
|
|
||||||
|
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
|
||||||
|
// ST7735 or ILI9163.
|
||||||
|
// cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||||
|
// cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
||||||
|
_panel_instance.config(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the backlight control. (delete if not necessary)
|
||||||
|
{
|
||||||
|
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||||
|
|
||||||
|
cfg.pin_bl = ST7789_BL; // Pin number to which the backlight is connected
|
||||||
|
cfg.invert = false; // true to invert the brightness of the backlight
|
||||||
|
// cfg.pwm_channel = 0;
|
||||||
|
|
||||||
|
_light_instance.config(cfg);
|
||||||
|
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAS_TOUCHSCREEN
|
||||||
|
// Configure settings for touch screen control.
|
||||||
|
{
|
||||||
|
auto cfg = _touch_instance.config();
|
||||||
|
|
||||||
|
cfg.pin_cs = -1;
|
||||||
|
cfg.x_min = 0;
|
||||||
|
cfg.x_max = TFT_HEIGHT - 1;
|
||||||
|
cfg.y_min = 0;
|
||||||
|
cfg.y_max = TFT_WIDTH - 1;
|
||||||
|
cfg.pin_int = SCREEN_TOUCH_INT;
|
||||||
|
cfg.bus_shared = true;
|
||||||
|
cfg.offset_rotation = TFT_OFFSET_ROTATION;
|
||||||
|
// cfg.freq = 2500000;
|
||||||
|
|
||||||
|
// I2C
|
||||||
|
cfg.i2c_port = TOUCH_I2C_PORT;
|
||||||
|
cfg.i2c_addr = TOUCH_SLAVE_ADDRESS;
|
||||||
|
#ifdef SCREEN_TOUCH_USE_I2C1
|
||||||
|
cfg.pin_sda = I2C_SDA1;
|
||||||
|
cfg.pin_scl = I2C_SCL1;
|
||||||
|
#else
|
||||||
|
cfg.pin_sda = I2C_SDA;
|
||||||
|
cfg.pin_scl = I2C_SCL;
|
||||||
|
#endif
|
||||||
|
// cfg.freq = 400000;
|
||||||
|
|
||||||
|
_touch_instance.config(cfg);
|
||||||
|
_panel_instance.setTouch(&_touch_instance);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setPanel(&_panel_instance); // Sets the panel to use.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static LGFX tft;
|
||||||
|
|
||||||
|
#elif defined(ILI9341_DRIVER)
|
||||||
|
|
||||||
|
#include <LovyanGFX.hpp> // Graphics and font library for ILI9341 driver chip
|
||||||
|
|
||||||
|
#if defined(ILI9341_BACKLIGHT_EN) && !defined(TFT_BL)
|
||||||
|
#define TFT_BL ILI9341_BACKLIGHT_EN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class LGFX : public lgfx::LGFX_Device
|
||||||
|
{
|
||||||
|
lgfx::Panel_ILI9341 _panel_instance;
|
||||||
|
lgfx::Bus_SPI _bus_instance;
|
||||||
|
lgfx::Light_PWM _light_instance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LGFX(void)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto cfg = _bus_instance.config();
|
||||||
|
|
||||||
|
// configure SPI
|
||||||
|
cfg.spi_host = ILI9341_SPI_HOST; // ESP32-S2,S3,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
|
||||||
|
cfg.spi_mode = 0;
|
||||||
|
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||||
|
// 80MHz by an integer)
|
||||||
|
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||||
|
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
|
||||||
|
cfg.use_lock = true; // Set to true to use transaction locking
|
||||||
|
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||||
|
// SPI_DMA_CH_AUTO=auto setting)
|
||||||
|
cfg.pin_sclk = TFT_SCLK; // Set SPI SCLK pin number
|
||||||
|
cfg.pin_mosi = TFT_MOSI; // Set SPI MOSI pin number
|
||||||
|
cfg.pin_miso = TFT_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||||
|
cfg.pin_dc = TFT_DC; // Set SPI DC pin number (-1 = disable)
|
||||||
|
|
||||||
|
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||||
|
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Set the display panel control.
|
||||||
|
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||||
|
|
||||||
|
cfg.pin_cs = TFT_CS; // Pin number where CS is connected (-1 = disable)
|
||||||
|
cfg.pin_rst = TFT_RST; // Pin number where RST is connected (-1 = disable)
|
||||||
|
cfg.pin_busy = TFT_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
||||||
|
|
||||||
|
// The following setting values are general initial values for each panel, so please comment out any
|
||||||
|
// unknown items and try them.
|
||||||
|
|
||||||
|
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||||
|
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||||
|
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||||
|
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||||
|
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is upside down)
|
||||||
|
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout
|
||||||
|
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||||
|
cfg.readable = true; // Set to true if data can be read
|
||||||
|
cfg.invert = false; // Set to true if the light/darkness of the panel is reversed
|
||||||
|
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||||
|
cfg.dlen_16bit =
|
||||||
|
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||||
|
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||||
|
|
||||||
|
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
|
||||||
|
// ST7735 or ILI9163.
|
||||||
|
cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||||
|
cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
||||||
|
_panel_instance.config(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the backlight control
|
||||||
|
{
|
||||||
|
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||||
|
|
||||||
|
cfg.pin_bl = TFT_BL; // Pin number to which the backlight is connected
|
||||||
|
cfg.invert = false; // true to invert the brightness of the backlight
|
||||||
|
// cfg.freq = 44100; // PWM frequency of backlight
|
||||||
|
// cfg.pwm_channel = 1; // PWM channel number to use
|
||||||
|
|
||||||
|
_light_instance.config(cfg);
|
||||||
|
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||||
|
}
|
||||||
|
|
||||||
|
setPanel(&_panel_instance);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static LGFX tft;
|
||||||
|
|
||||||
|
#elif defined(ST7735_CS)
|
||||||
|
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
|
||||||
|
|
||||||
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
|
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
|
||||||
|
|
||||||
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model)
|
#endif
|
||||||
|
|
||||||
|
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER)
|
||||||
|
#include "SPILock.h"
|
||||||
|
#include "TFTDisplay.h"
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||||
{
|
{
|
||||||
#ifdef SCREEN_ROTATE
|
#ifdef SCREEN_ROTATE
|
||||||
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);
|
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);
|
||||||
@@ -30,7 +345,7 @@ void TFTDisplay::display(void)
|
|||||||
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||||
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||||
if (isset != dblbuf_isset) {
|
if (isset != dblbuf_isset) {
|
||||||
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
|
tft.drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,8 +361,63 @@ void TFTDisplay::display(void)
|
|||||||
// Send a command to the display (low level function)
|
// Send a command to the display (low level function)
|
||||||
void TFTDisplay::sendCommand(uint8_t com)
|
void TFTDisplay::sendCommand(uint8_t com)
|
||||||
{
|
{
|
||||||
(void)com;
|
// handle display on/off directly
|
||||||
// Drop all commands to device (we just update the buffer)
|
switch (com) {
|
||||||
|
case DISPLAYON: {
|
||||||
|
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
|
||||||
|
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
|
||||||
|
#endif
|
||||||
|
#ifdef VTFT_CTRL
|
||||||
|
digitalWrite(VTFT_CTRL, LOW);
|
||||||
|
#endif
|
||||||
|
#ifndef M5STACK
|
||||||
|
tft.setBrightness(128);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DISPLAYOFF: {
|
||||||
|
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
|
||||||
|
digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON);
|
||||||
|
#endif
|
||||||
|
#ifdef VTFT_CTRL
|
||||||
|
digitalWrite(VTFT_CTRL, HIGH);
|
||||||
|
#endif
|
||||||
|
#ifndef M5STACK
|
||||||
|
tft.setBrightness(0);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop all other commands to device (we just update the buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
void TFTDisplay::flipScreenVertically()
|
||||||
|
{
|
||||||
|
#if defined(T_WATCH_S3)
|
||||||
|
LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation
|
||||||
|
tft.setRotation(0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TFTDisplay::hasTouch(void)
|
||||||
|
{
|
||||||
|
#ifndef M5STACK
|
||||||
|
return tft.touch() != nullptr;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
|
||||||
|
{
|
||||||
|
#ifndef M5STACK
|
||||||
|
return tft.getTouch(x, y);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFTDisplay::setDetected(uint8_t detected)
|
void TFTDisplay::setDetected(uint8_t detected)
|
||||||
@@ -62,23 +432,22 @@ bool TFTDisplay::connect()
|
|||||||
LOG_INFO("Doing TFT init\n");
|
LOG_INFO("Doing TFT init\n");
|
||||||
|
|
||||||
#ifdef TFT_BL
|
#ifdef TFT_BL
|
||||||
digitalWrite(TFT_BL, HIGH);
|
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
|
||||||
pinMode(TFT_BL, OUTPUT);
|
pinMode(TFT_BL, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ST7735_BACKLIGHT_EN
|
|
||||||
digitalWrite(ST7735_BACKLIGHT_EN, HIGH);
|
|
||||||
pinMode(ST7735_BACKLIGHT_EN, OUTPUT);
|
|
||||||
#endif
|
|
||||||
tft.init();
|
tft.init();
|
||||||
#ifdef M5STACK
|
#if defined(M5STACK)
|
||||||
tft.setRotation(1); // M5Stack has the TFT in landscape
|
tft.setRotation(0);
|
||||||
|
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
|
||||||
|
tft.setRotation(1); // T-Deck has the TFT in landscape
|
||||||
|
#elif defined(T_WATCH_S3)
|
||||||
|
tft.setRotation(2); // T-Watch S3 left-handed orientation
|
||||||
#else
|
#else
|
||||||
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||||
#endif
|
#endif
|
||||||
tft.fillScreen(TFT_BLACK);
|
tft.fillScreen(TFT_BLACK);
|
||||||
// tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -3,11 +3,10 @@
|
|||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An adapter class that allows using the TFT_eSPI library as if it was an OLEDDisplay implementation.
|
* An adapter class that allows using the LovyanGFX library as if it was an OLEDDisplay implementation.
|
||||||
*
|
*
|
||||||
* Remaining TODO:
|
* Remaining TODO:
|
||||||
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
||||||
* implement displayOn/displayOff to turn off the TFT device (and backlight)
|
|
||||||
* Use the fast NRF52 SPI API rather than the slow standard arduino version
|
* Use the fast NRF52 SPI API rather than the slow standard arduino version
|
||||||
*
|
*
|
||||||
* turn radio back on - currently with both on spi bus is fucked? or are we leaving chip select asserted?
|
* turn radio back on - currently with both on spi bus is fucked? or are we leaving chip select asserted?
|
||||||
@@ -18,11 +17,18 @@ class TFTDisplay : public OLEDDisplay
|
|||||||
/* constructor
|
/* constructor
|
||||||
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
|
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
|
||||||
*/
|
*/
|
||||||
TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model);
|
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
|
||||||
|
|
||||||
// Write the buffer to the display memory
|
// Write the buffer to the display memory
|
||||||
virtual void display(void) override;
|
virtual void display(void) override;
|
||||||
|
|
||||||
|
// Turn the display upside down
|
||||||
|
virtual void flipScreenVertically();
|
||||||
|
|
||||||
|
// Touch screen (static handlers)
|
||||||
|
static bool hasTouch(void);
|
||||||
|
static bool getTouch(int16_t *x, int16_t *y);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shim to make the abstraction happy
|
* shim to make the abstraction happy
|
||||||
*
|
*
|
||||||
@@ -38,4 +44,4 @@ class TFTDisplay : public OLEDDisplay
|
|||||||
|
|
||||||
// Connect to the display
|
// Connect to the display
|
||||||
virtual bool connect() override;
|
virtual bool connect() override;
|
||||||
};
|
};
|
||||||
424
src/graphics/fonts/OLEDDisplayFontsUA.cpp
Normal file
424
src/graphics/fonts/OLEDDisplayFontsUA.cpp
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
#include "OLEDDisplayFontsUA.h"
|
||||||
|
|
||||||
|
// Font generated or edited with the glyphEditor
|
||||||
|
const uint8_t ArialMT_Plain_10_UA[] PROGMEM = {
|
||||||
|
0x0A, // Width: 10
|
||||||
|
0x0D, // Height: 13
|
||||||
|
0x20, // First char: 32
|
||||||
|
0xE0, // Number of chars: 224
|
||||||
|
// Jump Table:
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 32
|
||||||
|
0x00, 0x00, 0x04, 0x03, // 33
|
||||||
|
0x00, 0x04, 0x05, 0x04, // 34
|
||||||
|
0x00, 0x09, 0x09, 0x06, // 35
|
||||||
|
0x00, 0x12, 0x0A, 0x06, // 36
|
||||||
|
0x00, 0x1C, 0x10, 0x09, // 37
|
||||||
|
0x00, 0x2C, 0x0E, 0x08, // 38
|
||||||
|
0x00, 0x3A, 0x01, 0x02, // 39
|
||||||
|
0x00, 0x3B, 0x06, 0x04, // 40
|
||||||
|
0x00, 0x41, 0x06, 0x04, // 41
|
||||||
|
0x00, 0x47, 0x05, 0x04, // 42
|
||||||
|
0x00, 0x4C, 0x09, 0x06, // 43
|
||||||
|
0x00, 0x55, 0x04, 0x03, // 44
|
||||||
|
0x00, 0x59, 0x03, 0x03, // 45
|
||||||
|
0x00, 0x5C, 0x04, 0x03, // 46
|
||||||
|
0x00, 0x60, 0x05, 0x04, // 47
|
||||||
|
0x00, 0x65, 0x0A, 0x06, // 48
|
||||||
|
0x00, 0x6F, 0x08, 0x05, // 49
|
||||||
|
0x00, 0x77, 0x0A, 0x06, // 50
|
||||||
|
0x00, 0x81, 0x0A, 0x06, // 51
|
||||||
|
0x00, 0x8B, 0x0B, 0x07, // 52
|
||||||
|
0x00, 0x96, 0x0A, 0x06, // 53
|
||||||
|
0x00, 0xA0, 0x0A, 0x06, // 54
|
||||||
|
0x00, 0xAA, 0x09, 0x06, // 55
|
||||||
|
0x00, 0xB3, 0x0A, 0x06, // 56
|
||||||
|
0x00, 0xBD, 0x0A, 0x06, // 57
|
||||||
|
0x00, 0xC7, 0x04, 0x03, // 58
|
||||||
|
0x00, 0xCB, 0x04, 0x03, // 59
|
||||||
|
0x00, 0xCF, 0x0A, 0x06, // 60
|
||||||
|
0x00, 0xD9, 0x09, 0x06, // 61
|
||||||
|
0x00, 0xE2, 0x09, 0x06, // 62
|
||||||
|
0x00, 0xEB, 0x0B, 0x07, // 63
|
||||||
|
0x00, 0xF6, 0x14, 0x0B, // 64
|
||||||
|
0x01, 0x0A, 0x0E, 0x08, // 65
|
||||||
|
0x01, 0x18, 0x0C, 0x07, // 66
|
||||||
|
0x01, 0x24, 0x0C, 0x07, // 67
|
||||||
|
0x01, 0x30, 0x0B, 0x07, // 68
|
||||||
|
0x01, 0x3B, 0x0C, 0x07, // 69
|
||||||
|
0x01, 0x47, 0x09, 0x06, // 70
|
||||||
|
0x01, 0x50, 0x0D, 0x08, // 71
|
||||||
|
0x01, 0x5D, 0x0C, 0x07, // 72
|
||||||
|
0x01, 0x69, 0x04, 0x03, // 73
|
||||||
|
0x01, 0x6D, 0x08, 0x05, // 74
|
||||||
|
0x01, 0x75, 0x0E, 0x08, // 75
|
||||||
|
0x01, 0x83, 0x0C, 0x07, // 76
|
||||||
|
0x01, 0x8F, 0x10, 0x09, // 77
|
||||||
|
0x01, 0x9F, 0x0C, 0x07, // 78
|
||||||
|
0x01, 0xAB, 0x0E, 0x08, // 79
|
||||||
|
0x01, 0xB9, 0x0B, 0x07, // 80
|
||||||
|
0x01, 0xC4, 0x0E, 0x08, // 81
|
||||||
|
0x01, 0xD2, 0x0C, 0x07, // 82
|
||||||
|
0x01, 0xDE, 0x0C, 0x07, // 83
|
||||||
|
0x01, 0xEA, 0x0B, 0x07, // 84
|
||||||
|
0x01, 0xF5, 0x0C, 0x07, // 85
|
||||||
|
0x02, 0x01, 0x0D, 0x08, // 86
|
||||||
|
0x02, 0x0E, 0x11, 0x0A, // 87
|
||||||
|
0x02, 0x1F, 0x0E, 0x08, // 88
|
||||||
|
0x02, 0x2D, 0x0D, 0x08, // 89
|
||||||
|
0x02, 0x3A, 0x0C, 0x07, // 90
|
||||||
|
0x02, 0x46, 0x06, 0x04, // 91
|
||||||
|
0x02, 0x4C, 0x06, 0x04, // 92
|
||||||
|
0x02, 0x52, 0x04, 0x03, // 93
|
||||||
|
0x02, 0x56, 0x09, 0x06, // 94
|
||||||
|
0x02, 0x5F, 0x0C, 0x07, // 95
|
||||||
|
0x02, 0x6B, 0x03, 0x03, // 96
|
||||||
|
0x02, 0x6E, 0x0A, 0x06, // 97
|
||||||
|
0x02, 0x78, 0x0A, 0x06, // 98
|
||||||
|
0x02, 0x82, 0x0A, 0x06, // 99
|
||||||
|
0x02, 0x8C, 0x0A, 0x06, // 100
|
||||||
|
0x02, 0x96, 0x0A, 0x06, // 101
|
||||||
|
0x02, 0xA0, 0x05, 0x04, // 102
|
||||||
|
0x02, 0xA5, 0x0A, 0x06, // 103
|
||||||
|
0x02, 0xAF, 0x0A, 0x06, // 104
|
||||||
|
0x02, 0xB9, 0x04, 0x03, // 105
|
||||||
|
0x02, 0xBD, 0x04, 0x03, // 106
|
||||||
|
0x02, 0xC1, 0x08, 0x05, // 107
|
||||||
|
0x02, 0xC9, 0x04, 0x03, // 108
|
||||||
|
0x02, 0xCD, 0x10, 0x09, // 109
|
||||||
|
0x02, 0xDD, 0x0A, 0x06, // 110
|
||||||
|
0x02, 0xE7, 0x0A, 0x06, // 111
|
||||||
|
0x02, 0xF1, 0x0A, 0x06, // 112
|
||||||
|
0x02, 0xFB, 0x0A, 0x06, // 113
|
||||||
|
0x03, 0x05, 0x05, 0x04, // 114
|
||||||
|
0x03, 0x0A, 0x08, 0x05, // 115
|
||||||
|
0x03, 0x12, 0x06, 0x04, // 116
|
||||||
|
0x03, 0x18, 0x0A, 0x06, // 117
|
||||||
|
0x03, 0x22, 0x09, 0x06, // 118
|
||||||
|
0x03, 0x2B, 0x0E, 0x08, // 119
|
||||||
|
0x03, 0x39, 0x0A, 0x06, // 120
|
||||||
|
0x03, 0x43, 0x09, 0x06, // 121
|
||||||
|
0x03, 0x4C, 0x0A, 0x06, // 122
|
||||||
|
0x03, 0x56, 0x06, 0x04, // 123
|
||||||
|
0x03, 0x5C, 0x04, 0x03, // 124
|
||||||
|
0x03, 0x60, 0x05, 0x04, // 125
|
||||||
|
0x03, 0x65, 0x09, 0x06, // 126
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 127
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 128
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 129
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 130
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 131
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 132
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 133
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 134
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 135
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 136
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 137
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 138
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 139
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 140
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 141
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 142
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 143
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 144
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 145
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 146
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 147
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 148
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 149
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 150
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 151
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 152
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 153
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 154
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 155
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 156
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 157
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 158
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 159
|
||||||
|
0xFF, 0xFF, 0x00, 0x0A, // 160
|
||||||
|
0x03, 0x6E, 0x04, 0x03, // 161
|
||||||
|
0x03, 0x72, 0x0A, 0x06, // 162
|
||||||
|
0x03, 0x7C, 0x0C, 0x07, // 163
|
||||||
|
0x03, 0x88, 0x0A, 0x06, // 164
|
||||||
|
0x03, 0x92, 0x09, 0x06, // 165
|
||||||
|
0x03, 0x9B, 0x04, 0x03, // 166
|
||||||
|
0x03, 0x9F, 0x0A, 0x06, // 167
|
||||||
|
0x03, 0xA9, 0x0C, 0x07, // 168
|
||||||
|
0x03, 0xB5, 0x0D, 0x08, // 169
|
||||||
|
0x03, 0xC2, 0x0C, 0x07, // 170
|
||||||
|
0x03, 0xCE, 0x0A, 0x06, // 171
|
||||||
|
0x03, 0xD8, 0x09, 0x06, // 172
|
||||||
|
0x03, 0xE1, 0x03, 0x03, // 173
|
||||||
|
0x03, 0xE4, 0x0D, 0x08, // 174
|
||||||
|
0x03, 0xF1, 0x0C, 0x07, // 175
|
||||||
|
0x03, 0xFD, 0x07, 0x05, // 176
|
||||||
|
0x04, 0x04, 0x0A, 0x06, // 177
|
||||||
|
0x04, 0x0E, 0x0C, 0x07, // 178
|
||||||
|
0x04, 0x1A, 0x0C, 0x07, // 179
|
||||||
|
0x04, 0x26, 0x07, 0x05, // 180
|
||||||
|
0x04, 0x2D, 0x0A, 0x06, // 181
|
||||||
|
0x04, 0x37, 0x09, 0x06, // 182
|
||||||
|
0x04, 0x40, 0x03, 0x03, // 183
|
||||||
|
0x04, 0x43, 0x0B, 0x07, // 184
|
||||||
|
0x04, 0x4E, 0x0B, 0x07, // 185
|
||||||
|
0x04, 0x59, 0x0C, 0x07, // 186
|
||||||
|
0x04, 0x65, 0x0A, 0x06, // 187
|
||||||
|
0x04, 0x6F, 0x10, 0x09, // 188
|
||||||
|
0x04, 0x7F, 0x10, 0x09, // 189
|
||||||
|
0x04, 0x8F, 0x10, 0x09, // 190
|
||||||
|
0x04, 0x9F, 0x0A, 0x06, // 191
|
||||||
|
0x04, 0xA9, 0x0C, 0x07, // 192
|
||||||
|
0x04, 0xB5, 0x0C, 0x07, // 193
|
||||||
|
0x04, 0xC1, 0x0C, 0x07, // 194
|
||||||
|
0x04, 0xCD, 0x0B, 0x07, // 195
|
||||||
|
0x04, 0xD8, 0x0C, 0x07, // 196
|
||||||
|
0x04, 0xE4, 0x0C, 0x07, // 197
|
||||||
|
0x04, 0xF0, 0x0C, 0x07, // 198
|
||||||
|
0x04, 0xFC, 0x0C, 0x07, // 199
|
||||||
|
0x05, 0x08, 0x0C, 0x07, // 200
|
||||||
|
0x05, 0x14, 0x0C, 0x07, // 201
|
||||||
|
0x05, 0x20, 0x0C, 0x07, // 202
|
||||||
|
0x05, 0x2C, 0x0C, 0x07, // 203
|
||||||
|
0x05, 0x38, 0x0C, 0x07, // 204
|
||||||
|
0x05, 0x44, 0x0C, 0x07, // 205
|
||||||
|
0x05, 0x50, 0x0C, 0x07, // 206
|
||||||
|
0x05, 0x5C, 0x0C, 0x07, // 207
|
||||||
|
0x05, 0x68, 0x0B, 0x07, // 208
|
||||||
|
0x05, 0x73, 0x0C, 0x07, // 209
|
||||||
|
0x05, 0x7F, 0x0B, 0x07, // 210
|
||||||
|
0x05, 0x8A, 0x0C, 0x07, // 211
|
||||||
|
0x05, 0x96, 0x0B, 0x07, // 212
|
||||||
|
0x05, 0xA1, 0x0C, 0x07, // 213
|
||||||
|
0x05, 0xAD, 0x0C, 0x07, // 214
|
||||||
|
0x05, 0xB9, 0x0C, 0x07, // 215
|
||||||
|
0x05, 0xC5, 0x0C, 0x07, // 216
|
||||||
|
0x05, 0xD1, 0x0E, 0x08, // 217
|
||||||
|
0x05, 0xDF, 0x0C, 0x07, // 218
|
||||||
|
0x05, 0xEB, 0x0C, 0x07, // 219
|
||||||
|
0x05, 0xF7, 0x0C, 0x07, // 220
|
||||||
|
0x06, 0x03, 0x0C, 0x07, // 221
|
||||||
|
0x06, 0x0F, 0x0C, 0x07, // 222
|
||||||
|
0x06, 0x1B, 0x0C, 0x07, // 223
|
||||||
|
0x06, 0x27, 0x0C, 0x07, // 224
|
||||||
|
0x06, 0x33, 0x0C, 0x07, // 225
|
||||||
|
0x06, 0x3F, 0x0C, 0x07, // 226
|
||||||
|
0x06, 0x4B, 0x0B, 0x07, // 227
|
||||||
|
0x06, 0x56, 0x0C, 0x07, // 228
|
||||||
|
0x06, 0x62, 0x0B, 0x07, // 229
|
||||||
|
0x06, 0x6D, 0x0C, 0x07, // 230
|
||||||
|
0x06, 0x79, 0x0C, 0x07, // 231
|
||||||
|
0x06, 0x85, 0x0C, 0x07, // 232
|
||||||
|
0x06, 0x91, 0x0C, 0x07, // 233
|
||||||
|
0x06, 0x9D, 0x0C, 0x07, // 234
|
||||||
|
0x06, 0xA9, 0x0C, 0x07, // 235
|
||||||
|
0x06, 0xB5, 0x0C, 0x07, // 236
|
||||||
|
0x06, 0xC1, 0x0C, 0x07, // 237
|
||||||
|
0x06, 0xCD, 0x0C, 0x07, // 238
|
||||||
|
0x06, 0xD9, 0x0C, 0x07, // 239
|
||||||
|
0x06, 0xE5, 0x0B, 0x07, // 240
|
||||||
|
0x06, 0xF0, 0x0C, 0x07, // 241
|
||||||
|
0x06, 0xFC, 0x0B, 0x07, // 242
|
||||||
|
0x07, 0x07, 0x0C, 0x07, // 243
|
||||||
|
0x07, 0x13, 0x0B, 0x07, // 244
|
||||||
|
0x07, 0x1E, 0x0C, 0x07, // 245
|
||||||
|
0x07, 0x2A, 0x0C, 0x07, // 246
|
||||||
|
0x07, 0x36, 0x0C, 0x07, // 247
|
||||||
|
0x07, 0x42, 0x0C, 0x07, // 248
|
||||||
|
0x07, 0x4E, 0x0E, 0x08, // 249
|
||||||
|
0x07, 0x5C, 0x0C, 0x07, // 250
|
||||||
|
0x07, 0x68, 0x0C, 0x07, // 251
|
||||||
|
0x07, 0x74, 0x0C, 0x07, // 252
|
||||||
|
0x07, 0x80, 0x0C, 0x07, // 253
|
||||||
|
0x07, 0x8C, 0x0C, 0x07, // 254
|
||||||
|
0x07, 0x98, 0x0C, 0x07, // 255
|
||||||
|
// Font Data:
|
||||||
|
0x00, 0x00, 0xF8, 0x02, // 33
|
||||||
|
0x38, 0x00, 0x00, 0x00, 0x38, // 34
|
||||||
|
0xA0, 0x03, 0xE0, 0x00, 0xB8, 0x03, 0xE0, 0x00, 0xB8, // 35
|
||||||
|
0x30, 0x01, 0x28, 0x02, 0xF8, 0x07, 0x48, 0x02, 0x90, 0x01, // 36
|
||||||
|
0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x30, 0x03, 0xC0, 0x00, 0xB0, 0x01, 0x48, 0x02, 0x80, 0x01, // 37
|
||||||
|
0x80, 0x01, 0x50, 0x02, 0x68, 0x02, 0xA8, 0x02, 0x18, 0x01, 0x80, 0x03, 0x80, 0x02, // 38
|
||||||
|
0x38, // 39
|
||||||
|
0xE0, 0x03, 0x10, 0x04, 0x08, 0x08, // 40
|
||||||
|
0x08, 0x08, 0x10, 0x04, 0xE0, 0x03, // 41
|
||||||
|
0x28, 0x00, 0x18, 0x00, 0x28, // 42
|
||||||
|
0x40, 0x00, 0x40, 0x00, 0xF0, 0x01, 0x40, 0x00, 0x40, // 43
|
||||||
|
0x00, 0x00, 0x00, 0x06, // 44
|
||||||
|
0x80, 0x00, 0x80, // 45
|
||||||
|
0x00, 0x00, 0x00, 0x02, // 46
|
||||||
|
0x00, 0x03, 0xE0, 0x00, 0x18, // 47
|
||||||
|
0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 48
|
||||||
|
0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0xF8, 0x03, // 49
|
||||||
|
0x10, 0x02, 0x08, 0x03, 0x88, 0x02, 0x48, 0x02, 0x30, 0x02, // 50
|
||||||
|
0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 51
|
||||||
|
0xC0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x80, // 52
|
||||||
|
0x60, 0x01, 0x38, 0x02, 0x28, 0x02, 0x28, 0x02, 0xC8, 0x01, // 53
|
||||||
|
0xF0, 0x01, 0x28, 0x02, 0x28, 0x02, 0x28, 0x02, 0xD0, 0x01, // 54
|
||||||
|
0x08, 0x00, 0x08, 0x03, 0xC8, 0x00, 0x38, 0x00, 0x08, // 55
|
||||||
|
0xB0, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 56
|
||||||
|
0x70, 0x01, 0x88, 0x02, 0x88, 0x02, 0x88, 0x02, 0xF0, 0x01, // 57
|
||||||
|
0x00, 0x00, 0x20, 0x02, // 58
|
||||||
|
0x00, 0x00, 0x20, 0x06, // 59
|
||||||
|
0x00, 0x00, 0x40, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 60
|
||||||
|
0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, // 61
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 62
|
||||||
|
0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0xC8, 0x02, 0x48, 0x00, 0x30, // 63
|
||||||
|
0x00, 0x00, 0xC0, 0x03, 0x30, 0x04, 0xD0, 0x09, 0x28, 0x0A, 0x28, 0x0A, 0xC8, 0x0B, 0x68, 0x0A, 0x10, 0x05, 0xE0, 0x04, // 64
|
||||||
|
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x88, 0x00, 0xB0, 0x00, 0xC0, 0x01, 0x00, 0x02, // 65
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 66
|
||||||
|
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 67
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, 0xE0, // 68
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 69
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x08, // 70
|
||||||
|
0x00, 0x00, 0xE0, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x50, 0x01, 0xC0, // 71
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 72
|
||||||
|
0x00, 0x00, 0xF8, 0x03, // 73
|
||||||
|
0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 74
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 75
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 76
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x30, 0x00, 0xF8, 0x03, // 77
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0x40, 0x00, 0x80, 0x01, 0xF8, 0x03, // 78
|
||||||
|
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 79
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 80
|
||||||
|
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x03, 0x08, 0x03, 0xF0, 0x02, // 81
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0xC8, 0x00, 0x30, 0x03, // 82
|
||||||
|
0x00, 0x00, 0x30, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x90, 0x01, // 83
|
||||||
|
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 84
|
||||||
|
0x00, 0x00, 0xF8, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 85
|
||||||
|
0x08, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x02, 0x80, 0x01, 0x70, 0x00, 0x08, // 86
|
||||||
|
0x18, 0x00, 0xE0, 0x01, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x18, // 87
|
||||||
|
0x00, 0x02, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 88
|
||||||
|
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x20, 0x00, 0x10, 0x00, 0x08, // 89
|
||||||
|
0x08, 0x03, 0x88, 0x02, 0xC8, 0x02, 0x68, 0x02, 0x38, 0x02, 0x18, 0x02, // 90
|
||||||
|
0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, // 91
|
||||||
|
0x18, 0x00, 0xE0, 0x00, 0x00, 0x03, // 92
|
||||||
|
0x08, 0x08, 0xF8, 0x0F, // 93
|
||||||
|
0x40, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, // 94
|
||||||
|
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 95
|
||||||
|
0x08, 0x00, 0x10, // 96
|
||||||
|
0x00, 0x00, 0x00, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // 97
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 98
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 99
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xF8, 0x03, // 100
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 101
|
||||||
|
0x20, 0x00, 0xF0, 0x03, 0x28, // 102
|
||||||
|
0x00, 0x00, 0xC0, 0x05, 0x20, 0x0A, 0x20, 0x0A, 0xE0, 0x07, // 103
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 104
|
||||||
|
0x00, 0x00, 0xE8, 0x03, // 105
|
||||||
|
0x00, 0x08, 0xE8, 0x07, // 106
|
||||||
|
0xF8, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, // 107
|
||||||
|
0x00, 0x00, 0xF8, 0x03, // 108
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 109
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 110
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 111
|
||||||
|
0x00, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 112
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xE0, 0x0F, // 113
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x20, // 114
|
||||||
|
0x40, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x20, 0x01, // 115
|
||||||
|
0x20, 0x00, 0xF8, 0x03, 0x20, 0x02, // 116
|
||||||
|
0x00, 0x00, 0xE0, 0x01, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 117
|
||||||
|
0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, // 118
|
||||||
|
0xE0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xE0, 0x01, // 119
|
||||||
|
0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 120
|
||||||
|
0x20, 0x00, 0xC0, 0x09, 0x00, 0x06, 0xC0, 0x01, 0x20, // 121
|
||||||
|
0x20, 0x02, 0x20, 0x03, 0xA0, 0x02, 0x60, 0x02, 0x20, 0x02, // 122
|
||||||
|
0x80, 0x00, 0x78, 0x0F, 0x08, 0x08, // 123
|
||||||
|
0x00, 0x00, 0xF8, 0x0F, // 124
|
||||||
|
0x08, 0x08, 0x78, 0x0F, 0x80, // 125
|
||||||
|
0xC0, 0x00, 0x40, 0x00, 0xC0, 0x00, 0x80, 0x00, 0xC0, // 126
|
||||||
|
0x00, 0x00, 0xA0, 0x0F, // 161
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x0F, 0x78, 0x02, 0x40, 0x01, // 162
|
||||||
|
0x40, 0x02, 0x70, 0x03, 0xC8, 0x02, 0x48, 0x02, 0x08, 0x02, 0x10, 0x02, // 163
|
||||||
|
0x00, 0x00, 0xE0, 0x01, 0x20, 0x01, 0x20, 0x01, 0xE0, 0x01, // 164
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x0C, // 165
|
||||||
|
0x00, 0x00, 0x38, 0x0F, // 166
|
||||||
|
0xD0, 0x04, 0x28, 0x09, 0x48, 0x09, 0x48, 0x0A, 0x90, 0x05, // 167
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0xA8, 0x02, 0xA0, 0x02, 0xA8, 0x02, 0x20, 0x02, // 168
|
||||||
|
0xE0, 0x00, 0x10, 0x01, 0x48, 0x02, 0xA8, 0x02, 0xA8, 0x02, 0x10, 0x01, 0xE0, // 169
|
||||||
|
0x00, 0x00, 0xF0, 0x01, 0x58, 0x03, 0x48, 0x02, 0x08, 0x02, 0x10, 0x01, // 170
|
||||||
|
0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, // 171
|
||||||
|
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, // 172
|
||||||
|
0x80, 0x00, 0x80, // 173
|
||||||
|
0xE0, 0x00, 0x10, 0x01, 0xE8, 0x02, 0x68, 0x02, 0xC8, 0x02, 0x10, 0x01, 0xE0, // 174
|
||||||
|
0x00, 0x00, 0x08, 0x02, 0x0A, 0x02, 0xF8, 0x03, 0x0A, 0x02, 0x08, 0x02, // 175
|
||||||
|
0x00, 0x00, 0x38, 0x00, 0x28, 0x00, 0x38, // 176
|
||||||
|
0x40, 0x02, 0x40, 0x02, 0xF0, 0x03, 0x40, 0x02, 0x40, 0x02, // 177
|
||||||
|
0x00, 0x00, 0x08, 0x02, 0x08, 0x02, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, // 178
|
||||||
|
0x00, 0x00, 0x20, 0x02, 0x20, 0x02, 0xE8, 0x03, 0x20, 0x02, 0x20, 0x02, // 179
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x30, // 180
|
||||||
|
0x00, 0x00, 0xE0, 0x0F, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 181
|
||||||
|
0x70, 0x00, 0xF8, 0x0F, 0x08, 0x00, 0xF8, 0x0F, 0x08, // 182
|
||||||
|
0x00, 0x00, 0x40, // 183
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA0, 0x02, 0xA8, 0x02, 0xC0, // 184
|
||||||
|
0x00, 0x00, 0xF0, 0x03, 0x40, 0x00, 0x80, 0x00, 0xF8, 0x03, 0x08, // 185
|
||||||
|
0x00, 0x00, 0xE0, 0x01, 0x50, 0x02, 0x50, 0x02, 0x10, 0x02, 0x20, 0x01, // 186
|
||||||
|
0x00, 0x00, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, // 187
|
||||||
|
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0xC0, 0x00, 0x20, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 188
|
||||||
|
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0x80, 0x00, 0x60, 0x00, 0x50, 0x02, 0x48, 0x03, 0xC0, 0x02, // 189
|
||||||
|
0x48, 0x00, 0x58, 0x00, 0x68, 0x03, 0x80, 0x00, 0x60, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 190
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0xE0, 0x03, 0x28, 0x02, // 191
|
||||||
|
0x00, 0x00, 0xF0, 0x03, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xF0, 0x03, // 192
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x88, 0x01, // 193
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 194
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x18, // 195
|
||||||
|
0x00, 0x00, 0x00, 0x02, 0xFC, 0x03, 0x04, 0x02, 0xFC, 0x03, 0x00, 0x02, // 196
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x08, 0x02, // 197
|
||||||
|
0x00, 0x00, 0xB8, 0x03, 0x40, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xB8, 0x03, // 198
|
||||||
|
0x00, 0x00, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 199
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0xF8, 0x03, // 200
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x08, 0x01, 0x90, 0x00, 0x48, 0x00, 0xE0, 0x03, // 201
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xA0, 0x00, 0x10, 0x01, 0x08, 0x02, // 202
|
||||||
|
0x00, 0x00, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 203
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x10, 0x00, 0x60, 0x00, 0x10, 0x00, 0xF8, 0x03, // 204
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 205
|
||||||
|
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 206
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 207
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 208
|
||||||
|
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 209
|
||||||
|
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 210
|
||||||
|
0x00, 0x00, 0x38, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xF8, 0x01, // 211
|
||||||
|
0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x88, 0x00, 0x70, // 212
|
||||||
|
0x00, 0x00, 0x18, 0x03, 0xA0, 0x00, 0x40, 0x00, 0xA0, 0x00, 0x18, 0x03, // 213
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, // 214
|
||||||
|
0x00, 0x00, 0x38, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 215
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, // 216
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x06, // 217
|
||||||
|
0x00, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 218
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xF8, 0x03, // 219
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 220
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 221
|
||||||
|
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xF0, 0x01, 0x08, 0x02, 0xF0, 0x01, // 222
|
||||||
|
0x00, 0x00, 0x30, 0x02, 0x48, 0x01, 0xC8, 0x00, 0x48, 0x00, 0xF8, 0x03, // 223
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x03, // 224
|
||||||
|
0x00, 0x00, 0xE0, 0x01, 0x50, 0x02, 0x50, 0x02, 0x48, 0x02, 0x88, 0x01, // 225
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 226
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, // 227
|
||||||
|
0x00, 0x00, 0x00, 0x02, 0xC0, 0x03, 0x20, 0x02, 0xE0, 0x03, 0x00, 0x02, // 228
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, // 229
|
||||||
|
0x00, 0x00, 0x60, 0x03, 0x80, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x60, 0x03, // 230
|
||||||
|
0x00, 0x00, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 231
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 232
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x98, 0x00, 0x40, 0x00, 0xE0, 0x03, // 233
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 234
|
||||||
|
0x00, 0x00, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 235
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 236
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 237
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 238
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 239
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 240
|
||||||
|
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x40, 0x02, // 241
|
||||||
|
0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, // 242
|
||||||
|
0x00, 0x00, 0x60, 0x00, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0xE0, 0x01, // 243
|
||||||
|
0x00, 0x00, 0xC0, 0x00, 0x20, 0x01, 0xE0, 0x03, 0x20, 0x01, 0xC0, // 244
|
||||||
|
0x00, 0x00, 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 245
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, // 246
|
||||||
|
0x00, 0x00, 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 247
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, // 248
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x06, // 249
|
||||||
|
0x00, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 250
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, 0xE0, 0x03, // 251
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 252
|
||||||
|
0x00, 0x00, 0x40, 0x01, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, // 253
|
||||||
|
0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, 0xC0, 0x01, // 254
|
||||||
|
0x00, 0x00, 0x40, 0x02, 0xA0, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0xE0, 0x03, // 255
|
||||||
|
};
|
||||||
11
src/graphics/fonts/OLEDDisplayFontsUA.h
Normal file
11
src/graphics/fonts/OLEDDisplayFontsUA.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef OLEDDISPLAYFONTSUA_h
|
||||||
|
#define OLEDDISPLAYFONTSUA_h
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
#include <Arduino.h>
|
||||||
|
#elif __MBED__
|
||||||
|
#define PROGMEM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const uint8_t ArialMT_Plain_10_UA[] PROGMEM;
|
||||||
|
#endif
|
||||||
@@ -14,7 +14,8 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
|
|||||||
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
|
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
|
||||||
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
|
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
|
||||||
|
|
||||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||||
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
||||||
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
||||||
const uint8_t imgInfoL1[] PROGMEM = {0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff};
|
const uint8_t imgInfoL1[] PROGMEM = {0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff};
|
||||||
|
|||||||
181
src/input/BBQ10Keyboard.cpp
Normal file
181
src/input/BBQ10Keyboard.cpp
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "BBQ10Keyboard.h"
|
||||||
|
|
||||||
|
#define _REG_VER 1
|
||||||
|
#define _REG_CFG 2
|
||||||
|
#define _REG_INT 3
|
||||||
|
#define _REG_KEY 4
|
||||||
|
#define _REG_BKL 5
|
||||||
|
#define _REG_DEB 6
|
||||||
|
#define _REG_FRQ 7
|
||||||
|
#define _REG_RST 8
|
||||||
|
#define _REG_FIF 9
|
||||||
|
|
||||||
|
#define _WRITE_MASK (1 << 7)
|
||||||
|
|
||||||
|
#define CFG_OVERFLOW_ON (1 << 0)
|
||||||
|
#define CFG_OVERFLOW_INT (1 << 1)
|
||||||
|
#define CFG_CAPSLOCK_INT (1 << 2)
|
||||||
|
#define CFG_NUMLOCK_INT (1 << 3)
|
||||||
|
#define CFG_KEY_INT (1 << 4)
|
||||||
|
#define CFG_PANIC_INT (1 << 5)
|
||||||
|
#define CFG_REPORT_MODS (1 << 6)
|
||||||
|
#define CFG_USE_MODS (1 << 7)
|
||||||
|
|
||||||
|
#define INT_OVERFLOW (1 << 0)
|
||||||
|
#define INT_CAPSLOCK (1 << 1)
|
||||||
|
#define INT_NUMLOCK (1 << 2)
|
||||||
|
#define INT_KEY (1 << 3)
|
||||||
|
#define INT_PANIC (1 << 4)
|
||||||
|
|
||||||
|
#define KEY_CAPSLOCK (1 << 5)
|
||||||
|
#define KEY_NUMLOCK (1 << 6)
|
||||||
|
#define KEY_COUNT_MASK (0x1F)
|
||||||
|
|
||||||
|
BBQ10Keyboard::BBQ10Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr) {}
|
||||||
|
|
||||||
|
void BBQ10Keyboard::begin(uint8_t addr, TwoWire *wire)
|
||||||
|
{
|
||||||
|
m_addr = addr;
|
||||||
|
m_wire = wire;
|
||||||
|
|
||||||
|
m_wire->begin();
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBQ10Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
|
||||||
|
{
|
||||||
|
m_addr = addr;
|
||||||
|
m_wire = nullptr;
|
||||||
|
writeCallback = w;
|
||||||
|
readCallback = r;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBQ10Keyboard::reset()
|
||||||
|
{
|
||||||
|
if (m_wire) {
|
||||||
|
m_wire->beginTransmission(m_addr);
|
||||||
|
m_wire->write(_REG_RST);
|
||||||
|
m_wire->endTransmission();
|
||||||
|
}
|
||||||
|
if (writeCallback) {
|
||||||
|
uint8_t data = 0;
|
||||||
|
writeCallback(m_addr, _REG_RST, &data, 0);
|
||||||
|
}
|
||||||
|
delay(100);
|
||||||
|
writeRegister(_REG_CFG, readRegister8(_REG_CFG) | CFG_REPORT_MODS);
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBQ10Keyboard::attachInterrupt(uint8_t pin, void (*func)(void)) const
|
||||||
|
{
|
||||||
|
pinMode(pin, INPUT_PULLUP);
|
||||||
|
::attachInterrupt(digitalPinToInterrupt(pin), func, RISING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBQ10Keyboard::detachInterrupt(uint8_t pin) const
|
||||||
|
{
|
||||||
|
::detachInterrupt(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBQ10Keyboard::clearInterruptStatus()
|
||||||
|
{
|
||||||
|
writeRegister(_REG_INT, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BBQ10Keyboard::status() const
|
||||||
|
{
|
||||||
|
return readRegister8(_REG_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BBQ10Keyboard::keyCount() const
|
||||||
|
{
|
||||||
|
return status() & KEY_COUNT_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
BBQ10Keyboard::KeyEvent BBQ10Keyboard::keyEvent() const
|
||||||
|
{
|
||||||
|
KeyEvent event = {.key = '\0', .state = StateIdle};
|
||||||
|
|
||||||
|
if (keyCount() == 0)
|
||||||
|
return event;
|
||||||
|
|
||||||
|
const uint16_t buf = readRegister16(_REG_FIF);
|
||||||
|
event.key = buf >> 8;
|
||||||
|
event.state = KeyState(buf & 0xFF);
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BBQ10Keyboard::backlight() const
|
||||||
|
{
|
||||||
|
return readRegister8(_REG_BKL) / 255.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBQ10Keyboard::setBacklight(float value)
|
||||||
|
{
|
||||||
|
writeRegister(_REG_BKL, value * 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BBQ10Keyboard::readRegister8(uint8_t reg) const
|
||||||
|
{
|
||||||
|
if (m_wire) {
|
||||||
|
m_wire->beginTransmission(m_addr);
|
||||||
|
m_wire->write(reg);
|
||||||
|
m_wire->endTransmission();
|
||||||
|
|
||||||
|
m_wire->requestFrom(m_addr, (uint8_t)1);
|
||||||
|
if (m_wire->available() < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return m_wire->read();
|
||||||
|
}
|
||||||
|
if (readCallback) {
|
||||||
|
uint8_t data;
|
||||||
|
readCallback(m_addr, reg, &data, 1);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BBQ10Keyboard::readRegister16(uint8_t reg) const
|
||||||
|
{
|
||||||
|
uint8_t data[2] = {0};
|
||||||
|
// uint8_t low = 0, high = 0;
|
||||||
|
if (m_wire) {
|
||||||
|
m_wire->beginTransmission(m_addr);
|
||||||
|
m_wire->write(reg);
|
||||||
|
m_wire->endTransmission();
|
||||||
|
|
||||||
|
m_wire->requestFrom(m_addr, (uint8_t)2);
|
||||||
|
if (m_wire->available() < 2)
|
||||||
|
return 0;
|
||||||
|
data[0] = m_wire->read();
|
||||||
|
data[1] = m_wire->read();
|
||||||
|
}
|
||||||
|
if (readCallback) {
|
||||||
|
readCallback(m_addr, reg, data, 2);
|
||||||
|
}
|
||||||
|
return (data[1] << 8) | data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBQ10Keyboard::writeRegister(uint8_t reg, uint8_t value)
|
||||||
|
{
|
||||||
|
uint8_t data[2];
|
||||||
|
data[0] = reg | _WRITE_MASK;
|
||||||
|
data[1] = value;
|
||||||
|
|
||||||
|
if (m_wire) {
|
||||||
|
m_wire->beginTransmission(m_addr);
|
||||||
|
m_wire->write(data, sizeof(uint8_t) * 2);
|
||||||
|
m_wire->endTransmission();
|
||||||
|
}
|
||||||
|
if (writeCallback) {
|
||||||
|
writeCallback(m_addr, data[0], &(data[1]), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/input/BBQ10Keyboard.h
Normal file
51
src/input/BBQ10Keyboard.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// Based on arturo182 arduino_bbq10kbd library https://github.com/arturo182/arduino_bbq10kbd
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
#define KEY_MOD_ALT (0x1A)
|
||||||
|
#define KEY_MOD_SHL (0x1B)
|
||||||
|
#define KEY_MOD_SHR (0x1C)
|
||||||
|
#define KEY_MOD_SYM (0x1D)
|
||||||
|
|
||||||
|
class BBQ10Keyboard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
|
||||||
|
|
||||||
|
enum KeyState { StateIdle = 0, StatePress, StateLongPress, StateRelease };
|
||||||
|
|
||||||
|
struct KeyEvent {
|
||||||
|
char key;
|
||||||
|
KeyState state;
|
||||||
|
};
|
||||||
|
|
||||||
|
BBQ10Keyboard();
|
||||||
|
|
||||||
|
void begin(uint8_t addr = BBQ10_KB_ADDR, TwoWire *wire = &Wire);
|
||||||
|
|
||||||
|
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = BBQ10_KB_ADDR);
|
||||||
|
|
||||||
|
void reset(void);
|
||||||
|
|
||||||
|
void attachInterrupt(uint8_t pin, void (*func)(void)) const;
|
||||||
|
void detachInterrupt(uint8_t pin) const;
|
||||||
|
void clearInterruptStatus(void);
|
||||||
|
|
||||||
|
uint8_t status(void) const;
|
||||||
|
uint8_t keyCount(void) const;
|
||||||
|
KeyEvent keyEvent(void) const;
|
||||||
|
|
||||||
|
float backlight() const;
|
||||||
|
void setBacklight(float value);
|
||||||
|
|
||||||
|
uint8_t readRegister8(uint8_t reg) const;
|
||||||
|
uint16_t readRegister16(uint8_t reg) const;
|
||||||
|
void writeRegister(uint8_t reg, uint8_t value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TwoWire *m_wire;
|
||||||
|
uint8_t m_addr;
|
||||||
|
i2c_com_fptr_t readCallback;
|
||||||
|
i2c_com_fptr_t writeCallback;
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user