mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-15 15:22:34 +00:00
Compare commits
1232 Commits
v1.3.5.e5b
...
v2.0.2.814
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8146e84200 | ||
|
|
1213ec2d57 | ||
|
|
f0279e7f92 | ||
|
|
1a50181ace | ||
|
|
d77bc239c1 | ||
|
|
cb283f4c57 | ||
|
|
728fc8cbad | ||
|
|
ad05b91f89 | ||
|
|
671e6cde44 | ||
|
|
7a3ad0afba | ||
|
|
d9f1704e36 | ||
|
|
32223a818c | ||
|
|
31e13d4de3 | ||
|
|
815bd6321b | ||
|
|
9f9bd40343 | ||
|
|
2331226bb6 | ||
|
|
80ff118f0f | ||
|
|
d6eeda7136 | ||
|
|
fb92e498f0 | ||
|
|
bf8d8886fd | ||
|
|
a695726f2a | ||
|
|
6dc4172110 | ||
|
|
25a9ee8eb6 | ||
|
|
e122232761 | ||
|
|
b13eaee6b3 | ||
|
|
f0f5107a5d | ||
|
|
0832cc50a8 | ||
|
|
962a3d0c55 | ||
|
|
6934e0bce7 | ||
|
|
3492d64177 | ||
|
|
057109dcac | ||
|
|
12fa08007d | ||
|
|
3562d34555 | ||
|
|
3ca6f645d4 | ||
|
|
6694d31d07 | ||
|
|
d15edf1955 | ||
|
|
e1ce037550 | ||
|
|
f9c376a524 | ||
|
|
26a907444c | ||
|
|
5c214bf4d8 | ||
|
|
5151a5641e | ||
|
|
9513209b70 | ||
|
|
f1416ac9f7 | ||
|
|
631db56a44 | ||
|
|
7b378d36cc | ||
|
|
8ab269e1b3 | ||
|
|
7652253b8d | ||
|
|
9805319940 | ||
|
|
e1e607cba3 | ||
|
|
d74bcd3583 | ||
|
|
9c0483975c | ||
|
|
2fb85dc129 | ||
|
|
d641adc0fc | ||
|
|
a7a020f431 | ||
|
|
a08ac5a47e | ||
|
|
30e5706eaa | ||
|
|
16444c190d | ||
|
|
3d9633a56c | ||
|
|
c0e630522c | ||
|
|
9422d31f55 | ||
|
|
087c7c19af | ||
|
|
3476b35fca | ||
|
|
950d5defda | ||
|
|
c6f060a24f | ||
|
|
1716c4d6f9 | ||
|
|
cda7a60734 | ||
|
|
ed26ab801c | ||
|
|
8874a6e488 | ||
|
|
657ae44b6f | ||
|
|
01381057c5 | ||
|
|
3dc6ed5672 | ||
|
|
764b48e04a | ||
|
|
4c931967c7 | ||
|
|
a547a791ba | ||
|
|
176072801b | ||
|
|
b941c51cf7 | ||
|
|
8a9fd6846e | ||
|
|
a49355133c | ||
|
|
09cdc20440 | ||
|
|
1c0dfe47c8 | ||
|
|
66623693eb | ||
|
|
7c692444e5 | ||
|
|
4ccb4393c5 | ||
|
|
b2e540b114 | ||
|
|
a5d1165c54 | ||
|
|
aa321e06dd | ||
|
|
8b84ac8a6c | ||
|
|
6c07fbfc12 | ||
|
|
04a478a5ad | ||
|
|
acfa186d44 | ||
|
|
3db504c470 | ||
|
|
3e5955be44 | ||
|
|
f1afbf2c0f | ||
|
|
20c559382d | ||
|
|
a3f1c02347 | ||
|
|
f5945d429e | ||
|
|
a3eced53bb | ||
|
|
20686cc66a | ||
|
|
5608fa32f7 | ||
|
|
a0c5defda6 | ||
|
|
25a3a09d5f | ||
|
|
593301146e | ||
|
|
5715ddc361 | ||
|
|
09ddde177c | ||
|
|
ef18b173cd | ||
|
|
ac4e88e0d2 | ||
|
|
3e82cd7dd4 | ||
|
|
b1f2025558 | ||
|
|
57ca5fea81 | ||
|
|
0ce018cf97 | ||
|
|
15a8710e69 | ||
|
|
cae75dcb6d | ||
|
|
d5e2b70b71 | ||
|
|
05b9fd04c6 | ||
|
|
4650989774 | ||
|
|
bcc77efb88 | ||
|
|
39c1637030 | ||
|
|
6d3028f213 | ||
|
|
b2969b2faf | ||
|
|
d07350e4a4 | ||
|
|
12df55c3d4 | ||
|
|
85b541bfd9 | ||
|
|
a9c6d6a80c | ||
|
|
32ad8aaa4e | ||
|
|
3d8e6aead2 | ||
|
|
2747600a3a | ||
|
|
b7ef63230b | ||
|
|
b4d6c8f37b | ||
|
|
6a907348b4 | ||
|
|
18ab8749ff | ||
|
|
a1ed5cdffc | ||
|
|
760d463bf5 | ||
|
|
5ed2a4e8bb | ||
|
|
60e95ef3bd | ||
|
|
5b648be2a5 | ||
|
|
0149171e1a | ||
|
|
b24caa1e06 | ||
|
|
8fa71afb72 | ||
|
|
309a3d5396 | ||
|
|
afafb3ba32 | ||
|
|
311835a231 | ||
|
|
1f9db0a8fe | ||
|
|
d6c9327aef | ||
|
|
0091863888 | ||
|
|
051ce5e09f | ||
|
|
6146b773cf | ||
|
|
8a4341fec4 | ||
|
|
154b7d256c | ||
|
|
548b0d0b53 | ||
|
|
e59361425f | ||
|
|
713e0f4260 | ||
|
|
8a1bf8cd86 | ||
|
|
f474953b51 | ||
|
|
d5ded53f05 | ||
|
|
82bcd391cd | ||
|
|
058689709f | ||
|
|
23c9fa0b56 | ||
|
|
eb29f10634 | ||
|
|
d5a9e3114a | ||
|
|
7417729482 | ||
|
|
d5c407c098 | ||
|
|
a1256818d9 | ||
|
|
689cec14aa | ||
|
|
04225826f6 | ||
|
|
86787e60f3 | ||
|
|
0c3ec9254d | ||
|
|
c0770402ce | ||
|
|
d7c98062ce | ||
|
|
497c0b7a47 | ||
|
|
d588dde007 | ||
|
|
3de0a3adfc | ||
|
|
b7ebe03ca8 | ||
|
|
a7fb88e293 | ||
|
|
6e1b1e3ed7 | ||
|
|
a66538fe55 | ||
|
|
b2913be086 | ||
|
|
602e65d898 | ||
|
|
338c9c1e0c | ||
|
|
9fac57b713 | ||
|
|
761804b17a | ||
|
|
c47401d729 | ||
|
|
aab52f1e8d | ||
|
|
4d2e44d64b | ||
|
|
41267a42f7 | ||
|
|
568434d0fa | ||
|
|
2c1bbf1ac6 | ||
|
|
1e97dcbb4c | ||
|
|
103c82bc2c | ||
|
|
f3fee5f4fb | ||
|
|
564feadc0d | ||
|
|
f05e0f3a81 | ||
|
|
cb26bc3871 | ||
|
|
f6251eef27 | ||
|
|
a9d6ef5990 | ||
|
|
60da55d6dd | ||
|
|
05147c016c | ||
|
|
f7655f3abe | ||
|
|
62b3509009 | ||
|
|
d817889255 | ||
|
|
d4ddcdd91e | ||
|
|
0bda4c2f76 | ||
|
|
be8da851a6 | ||
|
|
d4459a48b9 | ||
|
|
197bd2c3e1 | ||
|
|
d4ea9568ac | ||
|
|
97968213ff | ||
|
|
995885962d | ||
|
|
ddc1928bbb | ||
|
|
056a93f0c9 | ||
|
|
3d9845ff6d | ||
|
|
b615463981 | ||
|
|
d3540e82ff | ||
|
|
15ec8ba6a3 | ||
|
|
db12eab083 | ||
|
|
7d8c77a4b2 | ||
|
|
7c8c479b96 | ||
|
|
e29ae1cc91 | ||
|
|
089dd5b4d7 | ||
|
|
06285b599c | ||
|
|
1b6395b4e4 | ||
|
|
2236f74a55 | ||
|
|
43c9ab1faa | ||
|
|
b56f9b3b16 | ||
|
|
303396dfc3 | ||
|
|
075a53ced0 | ||
|
|
18ccb38824 | ||
|
|
c97831963b | ||
|
|
7c3dc076d2 | ||
|
|
b859347ecd | ||
|
|
ea87193c8f | ||
|
|
c1381b9ebd | ||
|
|
227cd93e67 | ||
|
|
f68f8e5547 | ||
|
|
943e6f02d4 | ||
|
|
01298a7b01 | ||
|
|
46aee8274f | ||
|
|
f76a2eeb9e | ||
|
|
3b7c0be842 | ||
|
|
49378a9145 | ||
|
|
139f61d03e | ||
|
|
f10d04591d | ||
|
|
e65d9e8ccd | ||
|
|
1fc3c0af70 | ||
|
|
e4751e34ae | ||
|
|
e922169e72 | ||
|
|
2b851ef6ae | ||
|
|
5f4b93aba2 | ||
|
|
b66d1a5dab | ||
|
|
867525eff8 | ||
|
|
7dcc981a2c | ||
|
|
38fed8a61e | ||
|
|
31c2c8a7a3 | ||
|
|
a081d28e36 | ||
|
|
93bb4f84f9 | ||
|
|
72e04edd7f | ||
|
|
b0d05522c0 | ||
|
|
f6119639bb | ||
|
|
fc57a9daa4 | ||
|
|
d8f44d7b1b | ||
|
|
efe2e90a03 | ||
|
|
45f9dee89a | ||
|
|
cc73d2c2f2 | ||
|
|
b1f789dddd | ||
|
|
d3e9dbf6a9 | ||
|
|
44529620ad | ||
|
|
7a9673dc37 | ||
|
|
27bcf67c0c | ||
|
|
7fde56b8ac | ||
|
|
6b614a2d6a | ||
|
|
1e1509fbf5 | ||
|
|
a3e67f8e4b | ||
|
|
028b25cfe8 | ||
|
|
2555e082d6 | ||
|
|
f8fa721c72 | ||
|
|
a7e0127793 | ||
|
|
603f60d86a | ||
|
|
6febf6b17c | ||
|
|
53aaf766dd | ||
|
|
4fa8d02b08 | ||
|
|
efa423c8ad | ||
|
|
43fb0d80f1 | ||
|
|
b25ace14e5 | ||
|
|
8734751bc4 | ||
|
|
5559a1edb0 | ||
|
|
bf503354f3 | ||
|
|
7b10441a28 | ||
|
|
994e396c00 | ||
|
|
6e22ee9061 | ||
|
|
b5fb0f60b0 | ||
|
|
a7fe69ed6b | ||
|
|
7f05298172 | ||
|
|
92a2505056 | ||
|
|
aae9d2fcf6 | ||
|
|
b59e928589 | ||
|
|
1db08b3b0e | ||
|
|
2cf3c105a1 | ||
|
|
505e4e8176 | ||
|
|
49a9973548 | ||
|
|
18af9d734d | ||
|
|
3e22aafea8 | ||
|
|
434db4347b | ||
|
|
b2c3b405b1 | ||
|
|
4bc8f6a6b9 | ||
|
|
4534d17d79 | ||
|
|
f88dde2f60 | ||
|
|
f8982ddaf8 | ||
|
|
784cd8c6f1 | ||
|
|
c3ab8f12cf | ||
|
|
b5adb7babc | ||
|
|
62c809a596 | ||
|
|
d2fe4426c1 | ||
|
|
984f0ca12c | ||
|
|
9d3eba9ea4 | ||
|
|
323f81eaba | ||
|
|
8d0e25fd82 | ||
|
|
20eaddee58 | ||
|
|
30b1bd85d9 | ||
|
|
09cce094d1 | ||
|
|
33a208e3c4 | ||
|
|
dd4c4fba80 | ||
|
|
a17c40ad09 | ||
|
|
9d73e606ac | ||
|
|
da12360105 | ||
|
|
ee1ae627a3 | ||
|
|
137a8dcfdf | ||
|
|
b2d753ed86 | ||
|
|
6e40102f26 | ||
|
|
511fe23b8a | ||
|
|
e433895873 | ||
|
|
5572195af9 | ||
|
|
cb956cd35b | ||
|
|
b551c7738e | ||
|
|
3d45c4dbd8 | ||
|
|
8681489cb7 | ||
|
|
ed328766b2 | ||
|
|
fb852ee6eb | ||
|
|
a6ee708b90 | ||
|
|
c9398e7b8a | ||
|
|
b591e35442 | ||
|
|
e50e15dc04 | ||
|
|
d4e65d8607 | ||
|
|
63ced7da7c | ||
|
|
03868d05db | ||
|
|
186374525a | ||
|
|
f116585c2a | ||
|
|
f4945729bc | ||
|
|
a3c76232c8 | ||
|
|
5bc41118e2 | ||
|
|
9445a96b3a | ||
|
|
a5761069ca | ||
|
|
2d4bfe183c | ||
|
|
bf4115a80f | ||
|
|
b2e84dfd29 | ||
|
|
004f6fa4d6 | ||
|
|
cefd4cd647 | ||
|
|
fd2ae61e3e | ||
|
|
7cda61ca01 | ||
|
|
98e1d52eaa | ||
|
|
1d09beb8a7 | ||
|
|
d44cce2928 | ||
|
|
51b3d4d06e | ||
|
|
a17ddaa951 | ||
|
|
9bd925226c | ||
|
|
e34ada3ff1 | ||
|
|
1ec1ff0773 | ||
|
|
7f935717db | ||
|
|
5b1d3a0c51 | ||
|
|
484f340023 | ||
|
|
ab0cf025c5 | ||
|
|
b384d9ea88 | ||
|
|
bb2094c4de | ||
|
|
6708121ba6 | ||
|
|
46a9bb3f7d | ||
|
|
62498d0935 | ||
|
|
c70184fbed | ||
|
|
4d2cb45f9f | ||
|
|
e5605cc6fe | ||
|
|
f7331a2e41 | ||
|
|
838271a14f | ||
|
|
b6b23907ed | ||
|
|
b240b9a088 | ||
|
|
b3a484f1e5 | ||
|
|
f3042ddf37 | ||
|
|
54816231e9 | ||
|
|
1c168d7d62 | ||
|
|
063c4904ff | ||
|
|
fefcbb147b | ||
|
|
53d48e8f61 | ||
|
|
ce5bce5cdc | ||
|
|
3597685b23 | ||
|
|
dc097c7230 | ||
|
|
b148781e4b | ||
|
|
5d8826e8ef | ||
|
|
39a51c7fbb | ||
|
|
129edde338 | ||
|
|
93cc278eee | ||
|
|
c34198264a | ||
|
|
054b12325d | ||
|
|
0f7a126828 | ||
|
|
7ff72fb981 | ||
|
|
0fe99595a9 | ||
|
|
b2ff628cec | ||
|
|
86a3bd6db8 | ||
|
|
73a5357d0e | ||
|
|
2faf507c0d | ||
|
|
cf124d97b8 | ||
|
|
482c0766af | ||
|
|
7e5a26fde5 | ||
|
|
e85af2f732 | ||
|
|
4df81008bc | ||
|
|
803dc69ccd | ||
|
|
42308cca5b | ||
|
|
ea991a4eee | ||
|
|
04db2d4410 | ||
|
|
076c1ed2ee | ||
|
|
75aa4ea325 | ||
|
|
e54be07dc0 | ||
|
|
d439d00e25 | ||
|
|
c4bea793af | ||
|
|
b53dcb932e | ||
|
|
371428d6ab | ||
|
|
1970d0c00f | ||
|
|
1dd7aa935f | ||
|
|
6b40f9d95c | ||
|
|
b3717d0396 | ||
|
|
82ba95833b | ||
|
|
28384df702 | ||
|
|
aee06f4738 | ||
|
|
ab282765d4 | ||
|
|
5d464badc8 | ||
|
|
68282682de | ||
|
|
2696b04138 | ||
|
|
31dc37150b | ||
|
|
e66d9d0add | ||
|
|
067bde321b | ||
|
|
84ec364ac2 | ||
|
|
32990856e3 | ||
|
|
a1bd5c9ea0 | ||
|
|
51f0e7879a | ||
|
|
0bdb90d133 | ||
|
|
e98c11ff89 | ||
|
|
8f84d7089c | ||
|
|
b0712c4186 | ||
|
|
8f92383ce4 | ||
|
|
c571fc9e24 | ||
|
|
05126bc6dc | ||
|
|
de56a370c6 | ||
|
|
daf189bf4b | ||
|
|
d95ec7e6b9 | ||
|
|
ac235bcabb | ||
|
|
ab4b3a50ee | ||
|
|
7f0fb2a2b6 | ||
|
|
ade1edfdfc | ||
|
|
4723faa95f | ||
|
|
93f83b0fcb | ||
|
|
8f84f7c0a5 | ||
|
|
48e4101f1c | ||
|
|
e6bb79f4c1 | ||
|
|
0bef3464f5 | ||
|
|
3c038a8c50 | ||
|
|
b8eb751316 | ||
|
|
5332db1eca | ||
|
|
9deda962aa | ||
|
|
c53434539b | ||
|
|
7f179deaf3 | ||
|
|
da29fa139f | ||
|
|
1d8a562fd9 | ||
|
|
0dbf97afab | ||
|
|
e5720fba3e | ||
|
|
498ac00b92 | ||
|
|
226a2dfe04 | ||
|
|
7e9a233296 | ||
|
|
ae311c838e | ||
|
|
de769db3bc | ||
|
|
5fa96c7fd1 | ||
|
|
2ee0c9a67a | ||
|
|
347af0210e | ||
|
|
d8455d687c | ||
|
|
34fef4c4e7 | ||
|
|
18bb373219 | ||
|
|
2f74f9ca15 | ||
|
|
5775c390f3 | ||
|
|
80826b8712 | ||
|
|
664d18cf58 | ||
|
|
bc2cddcb11 | ||
|
|
4949bda606 | ||
|
|
b4f75ad042 | ||
|
|
af4d11e17b | ||
|
|
e8f4a8b739 | ||
|
|
fae6693f8f | ||
|
|
0646ecdec4 | ||
|
|
544c89460f | ||
|
|
15089f5b01 | ||
|
|
8ef510035d | ||
|
|
864b1f754c | ||
|
|
883a2ebac0 | ||
|
|
bbe5b2e42c | ||
|
|
1b316b111f | ||
|
|
d0720620e8 | ||
|
|
cf4947d898 | ||
|
|
b5a8efa16b | ||
|
|
b38ae783b9 | ||
|
|
cbd8346c93 | ||
|
|
c0bfb979fd | ||
|
|
7c5a36ce38 | ||
|
|
fc729b0cbb | ||
|
|
0b81a25fda | ||
|
|
011db443ba | ||
|
|
b73e240f4d | ||
|
|
6de77ee310 | ||
|
|
0a8293a2d6 | ||
|
|
d0ad5dd4cf | ||
|
|
ab342ce904 | ||
|
|
140250ef03 | ||
|
|
ed90275370 | ||
|
|
e8b28faaf1 | ||
|
|
afcc7b6a56 | ||
|
|
e27a507a28 | ||
|
|
207f701f0a | ||
|
|
dd8cb1c7fb | ||
|
|
ccf93b8c23 | ||
|
|
4c6f3ead60 | ||
|
|
2d81d359b8 | ||
|
|
1f96d5d957 | ||
|
|
033f45d4da | ||
|
|
ae2c514ee7 | ||
|
|
80ddb81fac | ||
|
|
4bc29200be | ||
|
|
55c55fb705 | ||
|
|
0e2ab75bb0 | ||
|
|
128d20b290 | ||
|
|
ad9cc40b97 | ||
|
|
e0d3ac01b0 | ||
|
|
0f87adad7b | ||
|
|
9481461145 | ||
|
|
accd23eddc | ||
|
|
7c202b6069 | ||
|
|
e93b98ff98 | ||
|
|
b1ac2cf821 | ||
|
|
bfd1fecc2a | ||
|
|
c622a9b4be | ||
|
|
ade66cd8f4 | ||
|
|
397030b5a6 | ||
|
|
adc50f40b1 | ||
|
|
32d92d9b75 | ||
|
|
18f37981bb | ||
|
|
a8711bc54a | ||
|
|
eac2613743 | ||
|
|
4a0c18c4cd | ||
|
|
e376a3a28e | ||
|
|
a6bdff53c9 | ||
|
|
b5c5483ced | ||
|
|
601422e92b | ||
|
|
dbbe5e59ae | ||
|
|
b96dd6d36d | ||
|
|
e6b6e175b8 | ||
|
|
2ff549d458 | ||
|
|
a1230500fd | ||
|
|
17db87e042 | ||
|
|
42d2986cb8 | ||
|
|
cc054a13e2 | ||
|
|
60b4dbfdcd | ||
|
|
c446a0f222 | ||
|
|
f98e96cf1b | ||
|
|
3102777a71 | ||
|
|
ed95f382cf | ||
|
|
7f18c0fb77 | ||
|
|
52e4f93760 | ||
|
|
0167304300 | ||
|
|
7aaca3d486 | ||
|
|
bf3306fbc8 | ||
|
|
e375a8460b | ||
|
|
ff88900982 | ||
|
|
7f293bfda3 | ||
|
|
99de0a76a5 | ||
|
|
47ffb9c70d | ||
|
|
1231f926ea | ||
|
|
e05e888fca | ||
|
|
03580f5be8 | ||
|
|
90dabfea30 | ||
|
|
c8d7b1aba0 | ||
|
|
6065ef3a54 | ||
|
|
86c7eefc91 | ||
|
|
f7b12f0695 | ||
|
|
0c46ad91ef | ||
|
|
96cab75ccd | ||
|
|
a7138b7213 | ||
|
|
11590e33d3 | ||
|
|
a3a92d2d13 | ||
|
|
2088036521 | ||
|
|
7d0e16d1b6 | ||
|
|
35c77ef99c | ||
|
|
9244d03cf9 | ||
|
|
a50a461675 | ||
|
|
f78911666e | ||
|
|
f1e6585726 | ||
|
|
b8f862ac46 | ||
|
|
94a572aee6 | ||
|
|
e87ecc210a | ||
|
|
a9e7a33473 | ||
|
|
5621719eef | ||
|
|
cb3010b58c | ||
|
|
a27a07956f | ||
|
|
285ba9639e | ||
|
|
f54f60c31c | ||
|
|
84e438f72f | ||
|
|
f767fd5075 | ||
|
|
8fb8212434 | ||
|
|
8d5ffb7262 | ||
|
|
70e1a208d5 | ||
|
|
9d3cac7cdb | ||
|
|
84f1edab18 | ||
|
|
221843e176 | ||
|
|
0063ae6512 | ||
|
|
1922034c44 | ||
|
|
7f586f7099 | ||
|
|
0efa1b25c5 | ||
|
|
1b25ea714d | ||
|
|
fd27a40edb | ||
|
|
1013aff9b6 | ||
|
|
d7e5eb4d22 | ||
|
|
9a03b2e49d | ||
|
|
e7831f13c5 | ||
|
|
ddc3727155 | ||
|
|
ef9bfc9104 | ||
|
|
3bb645d4fe | ||
|
|
8f99258fc4 | ||
|
|
b54073a8a1 | ||
|
|
c85e9f53c7 | ||
|
|
4cfc229e77 | ||
|
|
bbd7c5063d | ||
|
|
05df849a6d | ||
|
|
ccbc01a753 | ||
|
|
d6d936b5d2 | ||
|
|
b028af0d82 | ||
|
|
86d3759f55 | ||
|
|
aadaf332cf | ||
|
|
4dea95d03f | ||
|
|
1253abd138 | ||
|
|
80e3cee006 | ||
|
|
ca9113ad05 | ||
|
|
63c8f15d38 | ||
|
|
73a1ea59f4 | ||
|
|
97712a9dc4 | ||
|
|
20e43fcf34 | ||
|
|
f66c8572b4 | ||
|
|
64f852e3f7 | ||
|
|
ea90e4d2de | ||
|
|
dd720f2fe6 | ||
|
|
808fef7e91 | ||
|
|
70e6dc3c67 | ||
|
|
279149e40f | ||
|
|
4588995fba | ||
|
|
11ae248c5e | ||
|
|
a0a5147c42 | ||
|
|
b8aac2c5b6 | ||
|
|
de22f20876 | ||
|
|
9b5211dc65 | ||
|
|
0b4fb72d58 | ||
|
|
7e03019cc4 | ||
|
|
780f4383f4 | ||
|
|
8148f06773 | ||
|
|
d5780af362 | ||
|
|
82ed7a2084 | ||
|
|
dd5fd3744d | ||
|
|
afb5fca6e1 | ||
|
|
95d75fdfee | ||
|
|
029a6b16ba | ||
|
|
9be3099ca6 | ||
|
|
b6126e6e63 | ||
|
|
d6dfdc314e | ||
|
|
78666e9b36 | ||
|
|
3abba0ce39 | ||
|
|
2c8e030b3d | ||
|
|
eed7408f00 | ||
|
|
cabd1eb8c0 | ||
|
|
f46c11a047 | ||
|
|
cdd5e16e25 | ||
|
|
a6c9a819f8 | ||
|
|
2e72397898 | ||
|
|
f554226226 | ||
|
|
2d1897a36f | ||
|
|
fe1ed3f284 | ||
|
|
3251cd510a | ||
|
|
7d0411cd15 | ||
|
|
1d1ccd6b19 | ||
|
|
3b8566747c | ||
|
|
3cc584d855 | ||
|
|
90d3cc2ff8 | ||
|
|
d125b0ec3c | ||
|
|
5e842dd735 | ||
|
|
bbc0baa31d | ||
|
|
31788feab1 | ||
|
|
2c37be58ac | ||
|
|
836782b3c1 | ||
|
|
cfc44cd608 | ||
|
|
519f31ed60 | ||
|
|
e04d6b3f56 | ||
|
|
25c851a929 | ||
|
|
0c8fb6e27f | ||
|
|
8490bdd14e | ||
|
|
22a5cf04d3 | ||
|
|
ddc5a59ece | ||
|
|
6382f67b89 | ||
|
|
401b5d92aa | ||
|
|
572f9f9295 | ||
|
|
96ce40040c | ||
|
|
d0a1aad7d1 | ||
|
|
ab0095cb05 | ||
|
|
591ae7a803 | ||
|
|
de47cc55a0 | ||
|
|
7e6c22f542 | ||
|
|
2fac581fa3 | ||
|
|
1155727a45 | ||
|
|
1c8e64319c | ||
|
|
ca1e687fd4 | ||
|
|
4c215530f6 | ||
|
|
472fb6e5b0 | ||
|
|
00846439d0 | ||
|
|
a10e56265b | ||
|
|
9fe2ddb082 | ||
|
|
a9ad314307 | ||
|
|
688ac3f8ee | ||
|
|
e79ef0dd35 | ||
|
|
9bc2b4d8d7 | ||
|
|
720cd62943 | ||
|
|
4073ba7572 | ||
|
|
39aa7f9880 | ||
|
|
71a9f46451 | ||
|
|
18d5712ecd | ||
|
|
295dca8415 | ||
|
|
7b438cd16b | ||
|
|
d285a2e70a | ||
|
|
2ad9e238e2 | ||
|
|
2d2f306982 | ||
|
|
7afc14991e | ||
|
|
86095323e5 | ||
|
|
01ac8d10b5 | ||
|
|
874d308b50 | ||
|
|
1f8878bd89 | ||
|
|
b39b58c87b | ||
|
|
fab20f5acf | ||
|
|
21f75686a4 | ||
|
|
4ad2e58047 | ||
|
|
e26975ca12 | ||
|
|
47da3b695a | ||
|
|
151321ac3c | ||
|
|
faac761dc0 | ||
|
|
5e2acc43f5 | ||
|
|
25a229ce85 | ||
|
|
41f9541f95 | ||
|
|
d64c552865 | ||
|
|
785c2b32da | ||
|
|
ba9d52da25 | ||
|
|
44ffdc5172 | ||
|
|
edd6f049cf | ||
|
|
97684c6c73 | ||
|
|
ade32b1827 | ||
|
|
69ac8c0353 | ||
|
|
fd27a814b7 | ||
|
|
f0518bc99a | ||
|
|
13a287ce5c | ||
|
|
7e7872605b | ||
|
|
a41735544b | ||
|
|
dcc6a4b5e7 | ||
|
|
c88ba583c6 | ||
|
|
b36cd32c03 | ||
|
|
43733ce150 | ||
|
|
0010231172 | ||
|
|
50300957db | ||
|
|
07d4773722 | ||
|
|
62aa740c93 | ||
|
|
c292e539d4 | ||
|
|
4de6d5bdb0 | ||
|
|
cf4c814b59 | ||
|
|
ca8e307976 | ||
|
|
b51b7d3eb7 | ||
|
|
ea7da3178b | ||
|
|
3011d09c8c | ||
|
|
d179f02519 | ||
|
|
67a7056025 | ||
|
|
930b023d10 | ||
|
|
4daf2cc3fa | ||
|
|
85f46d3231 | ||
|
|
d56094fb7c | ||
|
|
9c21064634 | ||
|
|
20d7d1b162 | ||
|
|
97a2bf6221 | ||
|
|
dff69157d6 | ||
|
|
38088253f8 | ||
|
|
7485c312dd | ||
|
|
0e560b376f | ||
|
|
6ff5ada7d6 | ||
|
|
cf331dc58b | ||
|
|
8c2af4f3d5 | ||
|
|
d7d574e0a7 | ||
|
|
5462d84bfc | ||
|
|
1efcd5e125 | ||
|
|
9fd7abf3d4 | ||
|
|
4a08f86f96 | ||
|
|
3f0ff45232 | ||
|
|
f8ee1ac4f9 | ||
|
|
f26441727c | ||
|
|
c725a6b65f | ||
|
|
9c6da233b9 | ||
|
|
0f2aa7660d | ||
|
|
004a6f9c25 | ||
|
|
d81b043f1d | ||
|
|
9f78dff25f | ||
|
|
e7dfd14917 | ||
|
|
bc47dd574b | ||
|
|
41d5ccc29f | ||
|
|
aead7a23f9 | ||
|
|
c9fd591942 | ||
|
|
c81fbd867d | ||
|
|
cfb76290cb | ||
|
|
46e13d23d9 | ||
|
|
45b2c169aa | ||
|
|
90baf9d8a0 | ||
|
|
a390fc7ea8 | ||
|
|
e0f912ab2a | ||
|
|
646d6f5615 | ||
|
|
cf00ac593f | ||
|
|
ff9f973a1d | ||
|
|
7a50ab4de2 | ||
|
|
c80f260fba | ||
|
|
a7d527c3c3 | ||
|
|
2e2c485f4c | ||
|
|
388865aba7 | ||
|
|
21c6e595a1 | ||
|
|
4a2522dbd3 | ||
|
|
877d72cbad | ||
|
|
63238cb810 | ||
|
|
e87c5d8d34 | ||
|
|
f9bbbfccb3 | ||
|
|
089c91a7ac | ||
|
|
9a5ff935f9 | ||
|
|
515a411e8c | ||
|
|
52f299ec49 | ||
|
|
9285316c78 | ||
|
|
cf380e6cb6 | ||
|
|
c3c359c0cb | ||
|
|
68465f294a | ||
|
|
f63b876b71 | ||
|
|
22fca01323 | ||
|
|
d4a4bcf91a | ||
|
|
d726ed6e7c | ||
|
|
349f6bf502 | ||
|
|
192c10d6d7 | ||
|
|
be8fb73204 | ||
|
|
bc9a4367d1 | ||
|
|
3d3511ceeb | ||
|
|
74e926ef00 | ||
|
|
f3a433f906 | ||
|
|
3c6a2f7bb6 | ||
|
|
1996a2a193 | ||
|
|
b40abbf3ad | ||
|
|
af335e9c06 | ||
|
|
8684fd1c49 | ||
|
|
49e47f3e6d | ||
|
|
d0a8a3018d | ||
|
|
7566ee1fea | ||
|
|
43d48d4fb9 | ||
|
|
2a6633a666 | ||
|
|
0146761850 | ||
|
|
0943e5f500 | ||
|
|
a1dc350231 | ||
|
|
d5a258cebd | ||
|
|
125f76d984 | ||
|
|
b127479961 | ||
|
|
d18aa2e7cb | ||
|
|
d301144efe | ||
|
|
058b5ceddd | ||
|
|
e85baf00c4 | ||
|
|
4a6cad6e46 | ||
|
|
bc05f98685 | ||
|
|
6e671d808a | ||
|
|
1df3dd5f78 | ||
|
|
c9822dee93 | ||
|
|
e1783df49f | ||
|
|
6b8afdadc2 | ||
|
|
f918548e44 | ||
|
|
a1b07ed6aa | ||
|
|
b059fb9e8e | ||
|
|
553b35d0ad | ||
|
|
04478081c6 | ||
|
|
7bd07db2a8 | ||
|
|
5c44c4f772 | ||
|
|
7ff940409e | ||
|
|
cb5c32490c | ||
|
|
e0b63c6692 | ||
|
|
dc8d1d9a84 | ||
|
|
710e2694ef | ||
|
|
7594140afc | ||
|
|
e793d933c6 | ||
|
|
9d8f9613d4 | ||
|
|
61427528b6 | ||
|
|
47ad27f9f6 | ||
|
|
77f096e56c | ||
|
|
5106433572 | ||
|
|
4458b470aa | ||
|
|
90957e6994 | ||
|
|
b73fd32f71 | ||
|
|
2a3272b7d0 | ||
|
|
3fd756900a | ||
|
|
beb8bc9e72 | ||
|
|
1ad5cdc93c | ||
|
|
e8e72d2e08 | ||
|
|
1d0badd468 | ||
|
|
9e87be4f22 | ||
|
|
97899aed26 | ||
|
|
0ee4ba4975 | ||
|
|
bbcccde787 | ||
|
|
42c285bc31 | ||
|
|
c831242f25 | ||
|
|
3c6f36c8f7 | ||
|
|
dfde6cc9c1 | ||
|
|
7816800012 | ||
|
|
ebf132ad21 | ||
|
|
67cf3018b5 | ||
|
|
eafbef0c2f | ||
|
|
4ab831c103 | ||
|
|
3df5ec0b11 | ||
|
|
c5c2765fb4 | ||
|
|
df9e9bc223 | ||
|
|
1ff0032c20 | ||
|
|
18024f1d25 | ||
|
|
313c50d6cf | ||
|
|
80e08f6de9 | ||
|
|
5a256323e2 | ||
|
|
45495c51e6 | ||
|
|
40ded630d0 | ||
|
|
432d06741e | ||
|
|
03b7f2f837 | ||
|
|
2e1b895791 | ||
|
|
9821a0535b | ||
|
|
0b666b827d | ||
|
|
235cacf9b9 | ||
|
|
db28a1562e | ||
|
|
f61d2d9eb4 | ||
|
|
5aef58e87f | ||
|
|
77a2054254 | ||
|
|
48ee995e0d | ||
|
|
c7dfd245e3 | ||
|
|
4e813b098a | ||
|
|
e57dbdd26c | ||
|
|
9512ea45de | ||
|
|
0d09767efd | ||
|
|
5828e6f423 | ||
|
|
c7a9ce7f49 | ||
|
|
95f091041b | ||
|
|
f33e6a0e66 | ||
|
|
fe8bfdb762 | ||
|
|
e8afd4fb4b | ||
|
|
71a43a97cc | ||
|
|
b34b26518b | ||
|
|
b9f25eb85c | ||
|
|
a7fbe024e4 | ||
|
|
1f7fee8e2a | ||
|
|
b8e7c6ee7a | ||
|
|
06b2ed4ebe | ||
|
|
32245a1a8d | ||
|
|
f6982ca726 | ||
|
|
03bbc5eff4 | ||
|
|
0767c0b0e8 | ||
|
|
0d574e35c6 | ||
|
|
b88e75cf2a | ||
|
|
6306c53bfe | ||
|
|
8db57601bf | ||
|
|
1b8830e7df | ||
|
|
0411401184 | ||
|
|
2ee003f2a1 | ||
|
|
5678221ead | ||
|
|
c5f3cad0f9 | ||
|
|
f3c15eb6cc | ||
|
|
e218bba87e | ||
|
|
c04d62158b | ||
|
|
03affc9e73 | ||
|
|
25bf97316d | ||
|
|
1ef70a2489 | ||
|
|
76ef240a3d | ||
|
|
3f171b29f7 | ||
|
|
dca6c27c9d | ||
|
|
2631a9324e | ||
|
|
c64f4bbb11 | ||
|
|
94f7e7037d | ||
|
|
a0b4b4efa1 | ||
|
|
d68d85590b | ||
|
|
800a4200ef | ||
|
|
9c50a76ea2 | ||
|
|
4a41694ec5 | ||
|
|
6bb3861e95 | ||
|
|
e8262540d4 | ||
|
|
2b6f632a50 | ||
|
|
bddab68110 | ||
|
|
c4f69cbcc0 | ||
|
|
85f5c7a40b | ||
|
|
e0c5e4d441 | ||
|
|
8dfdc11af9 | ||
|
|
ba1937de39 | ||
|
|
2e45d4f0fd | ||
|
|
b1f309545e | ||
|
|
22764425f7 | ||
|
|
5e8d49d24b | ||
|
|
53e9f4df46 | ||
|
|
33938f73a6 | ||
|
|
e4484270b1 | ||
|
|
964510ef52 | ||
|
|
b108540b08 | ||
|
|
db35b92b6f | ||
|
|
5d22efd8a8 | ||
|
|
49ccb77e43 | ||
|
|
3d0d45a695 | ||
|
|
2e39900f78 | ||
|
|
5e82423331 | ||
|
|
dd8111e737 | ||
|
|
9b02841506 | ||
|
|
3c5a096873 | ||
|
|
93521f7b39 | ||
|
|
bdcdc1485c | ||
|
|
fdc10acfdd | ||
|
|
ac93e3196e | ||
|
|
e5439c21ab | ||
|
|
7f9bb5748e | ||
|
|
894b091553 | ||
|
|
7576270423 | ||
|
|
6b8f83cd71 | ||
|
|
fdc3a6e432 | ||
|
|
49d8c581bd | ||
|
|
c15da3c104 | ||
|
|
12c46ced45 | ||
|
|
3ed9a05ac6 | ||
|
|
3b4c8ad0e2 | ||
|
|
d9e2e09149 | ||
|
|
97713b2daa | ||
|
|
7799e1b7e6 | ||
|
|
38913bb661 | ||
|
|
14cbc439ab | ||
|
|
6d15b9b82a | ||
|
|
2035ddf5a9 | ||
|
|
e91dedaab5 | ||
|
|
54bf02352f | ||
|
|
3f415e3e8e | ||
|
|
7133e6e89b | ||
|
|
e1d49a3632 | ||
|
|
f26fb9408e | ||
|
|
1e48989e2d | ||
|
|
e48285a33a | ||
|
|
7f0fd642ec | ||
|
|
5ee8c56c94 | ||
|
|
4940822ae8 | ||
|
|
8b42b78033 | ||
|
|
a7f4263db4 | ||
|
|
348e78718d | ||
|
|
0ec6771cf7 | ||
|
|
5e7b372345 | ||
|
|
6b0ce6b729 | ||
|
|
c07976438b | ||
|
|
eb6dd6b53d | ||
|
|
ea86f76393 | ||
|
|
b699e5e6cd | ||
|
|
4fb0cfa909 | ||
|
|
bb5b10eef3 | ||
|
|
b5cc304336 | ||
|
|
1812843363 | ||
|
|
628740d6d1 | ||
|
|
251365dca7 | ||
|
|
223c706e91 | ||
|
|
5e109d9648 | ||
|
|
2b769279ae | ||
|
|
8f8eff6f95 | ||
|
|
02fe597f3f | ||
|
|
4d611ba2f0 | ||
|
|
403a0b2ddc | ||
|
|
211273cc08 | ||
|
|
8ba0a9bf87 | ||
|
|
f84286d138 | ||
|
|
b980f3e311 | ||
|
|
399e053ebd | ||
|
|
d6b20ea623 | ||
|
|
caac2ecb83 | ||
|
|
7ae8601ba5 | ||
|
|
8f038ced15 | ||
|
|
3a1f20821e | ||
|
|
057131b459 | ||
|
|
1040b0988a | ||
|
|
2ca0290662 | ||
|
|
163774bb1f | ||
|
|
6a8724213e | ||
|
|
cf64da21fb | ||
|
|
c0d40895f8 | ||
|
|
50326fbb6b | ||
|
|
98cd19ea0f | ||
|
|
ca3192b3dc | ||
|
|
e1f28982cf | ||
|
|
8e996e3e63 | ||
|
|
53cc090814 | ||
|
|
bfc2d30a46 | ||
|
|
516dff5b09 | ||
|
|
4df0e910b8 | ||
|
|
3a5f492106 | ||
|
|
2dbb9075a3 | ||
|
|
e5715a0048 | ||
|
|
629db8c718 | ||
|
|
cc2a84afcd | ||
|
|
6c1dc0d71a | ||
|
|
9e97fac252 | ||
|
|
3a9086dfc5 | ||
|
|
a0f34a8d0a | ||
|
|
359b41d869 | ||
|
|
04723bd1a0 | ||
|
|
89d6990a92 | ||
|
|
96f20287ff | ||
|
|
d8ba25747b | ||
|
|
e66c01f0e6 | ||
|
|
aaea2e7456 | ||
|
|
92185e763d | ||
|
|
4de5944474 | ||
|
|
76e48178c8 | ||
|
|
75e7bccdfb | ||
|
|
3786b1ee15 | ||
|
|
f2dec07c8d | ||
|
|
701707a01b | ||
|
|
13fa7c1628 | ||
|
|
b957001629 | ||
|
|
9b6b224af4 | ||
|
|
4785367915 | ||
|
|
d640478289 | ||
|
|
b8b1a5cfb7 | ||
|
|
770f17f382 | ||
|
|
8ea3ebf74b | ||
|
|
cbf238652e | ||
|
|
c17cd47689 | ||
|
|
d2c278a856 | ||
|
|
213d9512f1 | ||
|
|
81588d8bdc | ||
|
|
3c1407c7d2 | ||
|
|
98c8eaaaf0 | ||
|
|
e7a825d1ba | ||
|
|
1d2551350d | ||
|
|
a13157ebde | ||
|
|
a0971ebe9c | ||
|
|
8733bcb52e | ||
|
|
7c12234a9c | ||
|
|
823e6cb1ed | ||
|
|
29e378a11e | ||
|
|
692278343b | ||
|
|
c60d4c1ecc | ||
|
|
6d01f9aa89 | ||
|
|
616c7d7b0e | ||
|
|
c6a2e26876 | ||
|
|
6b012ca5b0 | ||
|
|
93466baa87 | ||
|
|
137328f567 | ||
|
|
838f00c7d7 | ||
|
|
293921e95a | ||
|
|
b82bf5c729 | ||
|
|
90df7c2488 | ||
|
|
8c1a81c03a | ||
|
|
6fe9f0b42f | ||
|
|
43f6f61472 | ||
|
|
ed62b6916c | ||
|
|
cf45e4fce5 | ||
|
|
136e2e96f7 | ||
|
|
7c071e2361 | ||
|
|
0b85e97087 | ||
|
|
81d1cc1003 | ||
|
|
748416d9e3 | ||
|
|
da6d49385c | ||
|
|
f279f9614e | ||
|
|
9097475149 | ||
|
|
5327d6162a | ||
|
|
5d7990667d | ||
|
|
79a41bd81c | ||
|
|
6a3d81eff8 | ||
|
|
7cd66b2b68 | ||
|
|
8124ecbfd8 | ||
|
|
7df1a64b52 | ||
|
|
e51b7c3c32 | ||
|
|
0c285aac6e | ||
|
|
fbeb554186 | ||
|
|
87da779478 | ||
|
|
1082c5d771 | ||
|
|
3933d24d62 | ||
|
|
fc0508f254 | ||
|
|
bb22b6ec58 | ||
|
|
ddb9678377 | ||
|
|
dc20cbb672 | ||
|
|
a10ea604af | ||
|
|
fb1caa51d0 | ||
|
|
7e977aea00 | ||
|
|
ecc114f1cd | ||
|
|
b76424db50 | ||
|
|
f511baba9a | ||
|
|
b056081d3c | ||
|
|
0e4699d8b6 | ||
|
|
794167c701 | ||
|
|
b59368ca3c | ||
|
|
a4bdef4151 | ||
|
|
478274aff1 | ||
|
|
02066cc8b9 | ||
|
|
309de52f5c | ||
|
|
340737f2a8 | ||
|
|
9bd970c55e | ||
|
|
6eab8f84d1 | ||
|
|
a31bf71ec1 | ||
|
|
14eef42762 | ||
|
|
ef85b74cec | ||
|
|
16ae867c2d | ||
|
|
0643dcd745 | ||
|
|
69ed477040 | ||
|
|
0f5b0b5f00 | ||
|
|
11323acb23 | ||
|
|
a20ba7e686 | ||
|
|
10a7071300 | ||
|
|
eae9673ddb | ||
|
|
6e9cf82b68 | ||
|
|
06aae85e45 | ||
|
|
0035469790 | ||
|
|
028999697e | ||
|
|
b7aa1397c7 | ||
|
|
279def7911 | ||
|
|
d73d3ca959 | ||
|
|
a2df441e1f | ||
|
|
998c90d326 | ||
|
|
0c600363c8 | ||
|
|
6c2d45d866 | ||
|
|
cf532496a4 | ||
|
|
92d32f722d | ||
|
|
d246c31548 | ||
|
|
19589bf12d | ||
|
|
ba984aebfa |
@@ -1,11 +0,0 @@
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/ubuntu/.devcontainer/base.Dockerfile
|
||||
|
||||
# [Choice] Ubuntu version: bionic, focal
|
||||
ARG VARIANT="focal"
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}
|
||||
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get -y install python3-distutils python3-pip
|
||||
RUN pip3 install platformio meshtastic adafruit-nrfutil
|
||||
RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v3.15.8/protoc-3.15.8-linux-x86_64.zip -O /tmp/protoc.zip && cd /tmp && unzip protoc.zip && chmod a+x bin/protoc && cp bin/protoc /usr/local/bin
|
||||
@@ -1,32 +0,0 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/ubuntu
|
||||
{
|
||||
"name": "Ubuntu",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
// Update 'VARIANT' to pick an Ubuntu version: focal, bionic
|
||||
"args": { "VARIANT": "focal" }
|
||||
},
|
||||
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash"
|
||||
},
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"platformio.platformio-ide",
|
||||
"xaver.clang-format"
|
||||
],
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "uname -a",
|
||||
|
||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "vscode",
|
||||
|
||||
"postCreateCommand": "git submodule update --init"
|
||||
}
|
||||
146
.github/workflows/main.yml
vendored
146
.github/workflows/main.yml
vendored
@@ -1,146 +0,0 @@
|
||||
name: Continuous Integration (Legacy serial build)
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the master branch
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
ci-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Install cppcheck
|
||||
run: |
|
||||
sudo apt-get install -y cppcheck
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools and install platformio
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Check everything
|
||||
run: bin/check-all.sh
|
||||
|
||||
ci-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
# We actually want to run this every time
|
||||
# if: steps.cache-pip.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
|
||||
# - name: Cache platformio
|
||||
# uses: actions/cache@v1
|
||||
# id: cache-platformio # needed in if test
|
||||
# with:
|
||||
# path: ~/.platformio
|
||||
# key: ${{ runner.os }}-platformio
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/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
|
||||
|
||||
# We now run integration test before other build steps (to quickly see runtime failures)
|
||||
- name: Build for native
|
||||
run: platformio run -e native
|
||||
- name: Integration test
|
||||
run: |
|
||||
.pio/build/native/program &
|
||||
sleep 20 # 5 seconds was not enough
|
||||
echo "Simulator started, launching python test..."
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||
|
||||
- name: Cat bin/build-all.sh
|
||||
run: |
|
||||
cat bin/build-all.sh
|
||||
|
||||
- name: Build everything
|
||||
run: bin/build-all.sh
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware-${{ steps.version.outputs.version }}.zip
|
||||
path: release/archive/firmware-${{ steps.version.outputs.version }}.zip
|
||||
retention-days: 90
|
||||
|
||||
- name: Store debugging elf files as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: debug-elfs
|
||||
path: release/archive/elfs-*.zip
|
||||
retention-days: 7
|
||||
|
||||
- name: Download firmware.zip
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: firmware-${{ steps.version.outputs.version }}.zip
|
||||
path: ./
|
||||
|
||||
- name: Pull request artifacts
|
||||
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
|
||||
uses: gavv/pull-request-artifacts@v1.0.0
|
||||
with:
|
||||
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
artifacts-branch: artifacts
|
||||
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip
|
||||
248
.github/workflows/main_matrix.yml
vendored
248
.github/workflows/main_matrix.yml
vendored
@@ -1,19 +1,18 @@
|
||||
name: Continuous Integration
|
||||
name: CI
|
||||
on:
|
||||
# # Triggers the workflow on push but only for the master branch
|
||||
push:
|
||||
branches: [master]
|
||||
branches: [master, develop]
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "**.yml"
|
||||
- "version.properties"
|
||||
|
||||
# Note: This is different from "pull_request". Need to specify ref when doing checkouts.
|
||||
pull_request_target:
|
||||
branches: [master]
|
||||
branches: [master, develop]
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "**.yml"
|
||||
#- "**.yml"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -34,10 +33,17 @@ jobs:
|
||||
- board: heltec-v2.1
|
||||
- board: tbeam0.7
|
||||
- board: meshtastic-diy-v1
|
||||
- board: rak4631_5005
|
||||
- board: rak4631_19003
|
||||
- board: rak4631_5005_eink
|
||||
- board: meshtastic-dr-dev
|
||||
- board: rak4631
|
||||
- board: rak4631_eink
|
||||
- board: t-echo
|
||||
- board: nano-g1
|
||||
- board: station-g1
|
||||
- board: m5stack-core
|
||||
- board: m5stack-coreink
|
||||
- board: tbeam-s3-core
|
||||
- board: feather_diy
|
||||
# - board: pico
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -53,12 +59,12 @@ jobs:
|
||||
sudo apt-get install -y cppcheck
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
@@ -92,6 +98,12 @@ jobs:
|
||||
- board: heltec-v2.1
|
||||
- board: tbeam0.7
|
||||
- board: meshtastic-diy-v1
|
||||
- board: meshtastic-dr-dev
|
||||
- board: nano-g1
|
||||
- board: station-g1
|
||||
- board: m5stack-core
|
||||
- board: m5stack-coreink
|
||||
- board: tbeam-s3-core
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -103,12 +115,12 @@ jobs:
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
@@ -117,7 +129,7 @@ jobs:
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
@@ -126,7 +138,7 @@ jobs:
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/meshtastic-web"
|
||||
repo: "meshtastic/web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -139,18 +151,26 @@ jobs:
|
||||
- name: Build ESP32
|
||||
run: bin/build-esp32.sh ${{ matrix.board }}
|
||||
|
||||
- name: Pull OTA Firmware
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/firmware-ota"
|
||||
file: "firmware.bin"
|
||||
target: "release/bleota.bin"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.bin
|
||||
release/*.elf
|
||||
retention-days: 90
|
||||
retention-days: 30
|
||||
|
||||
build-nrf52:
|
||||
strategy:
|
||||
@@ -158,10 +178,11 @@ jobs:
|
||||
max-parallel: 2
|
||||
matrix:
|
||||
include:
|
||||
- board: rak4631_5005
|
||||
- board: rak4631_19003
|
||||
- board: rak4631_5005_eink
|
||||
- board: rak4631
|
||||
- board: rak4631_eink
|
||||
- board: t-echo
|
||||
- board: pca10059_diy_eink
|
||||
- board: feather_diy
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -173,12 +194,12 @@ jobs:
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
@@ -187,7 +208,7 @@ jobs:
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
@@ -197,17 +218,72 @@ jobs:
|
||||
run: bin/build-nrf52.sh ${{ matrix.board }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.uf2
|
||||
release/*.elf
|
||||
retention-days: 90
|
||||
release/*.zip
|
||||
retention-days: 30
|
||||
|
||||
build-rpi2040:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 2
|
||||
matrix:
|
||||
include:
|
||||
- board: pico
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Build Raspberry Pi 2040
|
||||
run: ./bin/build-rpi2040.sh ${{ matrix.board }}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/*.uf2
|
||||
release/*.elf
|
||||
retention-days: 30
|
||||
|
||||
build-native:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -220,12 +296,12 @@ jobs:
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Cache python libs
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v3
|
||||
id: cache-pip # needed in if test
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
@@ -234,7 +310,8 @@ jobs:
|
||||
- name: Upgrade python tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
pip install -U platformio adafruit-nrfutil
|
||||
pip install -U meshtastic --pre
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
@@ -254,18 +331,18 @@ jobs:
|
||||
run: bin/build-native.sh
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-native-${{ steps.version.outputs.version }}.zip
|
||||
path: |
|
||||
release/meshtasticd_linux_amd64
|
||||
release/device-*.sh
|
||||
release/device-*.bat
|
||||
retention-days: 90
|
||||
retention-days: 30
|
||||
|
||||
after-checks:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -279,7 +356,7 @@ jobs:
|
||||
|
||||
gather-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-esp32, build-nrf52, build-native]
|
||||
needs: [build-esp32, build-nrf52, build-native, build-rpi2040]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
@@ -287,30 +364,31 @@ jobs:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: ./
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Move files up
|
||||
run: mv -b -t ./ ./*tbeam-*/littlefs*.bin ./*tbeam-*/system-info.bin ./**/firmware*.bin ./**/*.uf2 ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
|
||||
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ steps.version.outputs.version }}
|
||||
path: |
|
||||
./*.bin
|
||||
./*.uf2
|
||||
./firmware-*-ota.zip
|
||||
./meshtasticd_linux_amd64
|
||||
./device-*.sh
|
||||
./device-*.bat
|
||||
retention-days: 90
|
||||
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ steps.version.outputs.version }}
|
||||
path: ./output
|
||||
@@ -319,15 +397,20 @@ jobs:
|
||||
- name: Show artifacts
|
||||
run: ls -lR
|
||||
|
||||
- name: Device scripts permissions
|
||||
run: |
|
||||
chmod +x ./output/device-install.sh
|
||||
chmod +x ./output/device-update.sh
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: debug-elfs-${{ steps.version.outputs.version }}.zip
|
||||
path: ./*.elf
|
||||
retention-days: 90
|
||||
retention-days: 30
|
||||
|
||||
- name: Create request artifacts
|
||||
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
|
||||
@@ -340,3 +423,88 @@ jobs:
|
||||
artifacts-branch: device
|
||||
artifacts-dir: pr
|
||||
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip
|
||||
|
||||
release-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
needs: [gather-artifacts, after-checks]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: firmware-${{ steps.version.outputs.version }}
|
||||
path: ./output
|
||||
|
||||
- name: Device scripts permissions
|
||||
run: |
|
||||
chmod +x ./output/device-install.sh
|
||||
chmod +x ./output/device-update.sh
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: debug-elfs-${{ steps.version.outputs.version }}.zip
|
||||
path: ./elfs
|
||||
|
||||
- name: Zip Elfs
|
||||
run: zip -j -r ./debug-elfs-${{ steps.version.outputs.version }}.zip ./elfs
|
||||
|
||||
# For diagnostics
|
||||
- name: Show artifacts
|
||||
run: ls -lR
|
||||
|
||||
- name: Create release
|
||||
uses: actions/create-release@v1
|
||||
id: create_release
|
||||
with:
|
||||
draft: true
|
||||
prerelease: true
|
||||
release_name: Meshtastic Firmware ${{ steps.version.outputs.version }}
|
||||
tag_name: v${{ steps.version.outputs.version }}
|
||||
body: |
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Add bins to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./firmware-${{ steps.version.outputs.version }}.zip
|
||||
asset_name: firmware-${{ steps.version.outputs.version }}.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
- name: Add debug elfs to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./debug-elfs-${{ steps.version.outputs.version }}.zip
|
||||
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
- name: Bump version.properties
|
||||
run: >-
|
||||
bin/bump_version.py
|
||||
|
||||
- name: Create version.properties pull request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
add-paths: |
|
||||
version.properties
|
||||
|
||||
92
.github/workflows/release.yml
vendored
92
.github/workflows/release.yml
vendored
@@ -1,92 +0,0 @@
|
||||
name: Make Release
|
||||
on:
|
||||
# Can optionally take parameters from the github UI, more info here https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/#:~:text=You%20can%20now%20create%20workflows,the%20workflow%20is%20run%20on.
|
||||
workflow_dispatch:
|
||||
# inputs:
|
||||
|
||||
# Only want to run if version.properties is bumped in master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- "version.properties"
|
||||
|
||||
jobs:
|
||||
release-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
# Will be available in steps.version.outputs.version
|
||||
- name: Get release version string
|
||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||
id: version
|
||||
# Note: we don't use caches on release builds because we don't want to accidentally not have a virgin build machine
|
||||
|
||||
- name: Upgrade python tools
|
||||
# We actually want to run this every time
|
||||
# if: steps.cache-pip.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil littlefs-python
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
pio upgrade
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
with:
|
||||
repo: "meshtastic/meshtastic-web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
run: |
|
||||
tar -xf build.tar -C data/static
|
||||
rm build.tar
|
||||
|
||||
- name: Build everything
|
||||
run: bin/build-all.sh
|
||||
|
||||
- name: Create release
|
||||
uses: actions/create-release@v1
|
||||
id: create_release
|
||||
with:
|
||||
draft: true
|
||||
prerelease: true
|
||||
release_name: ${{ steps.version.outputs.version }} alpha
|
||||
tag_name: v${{ steps.version.outputs.version }}
|
||||
body: |
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Add bins to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: release/archive/firmware-${{ steps.version.outputs.version }}.zip
|
||||
asset_name: firmware-${{ steps.version.outputs.version }}.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
- name: Add debug elfs to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: release/archive/elfs-${{ steps.version.outputs.version }}.zip
|
||||
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
|
||||
asset_content_type: application/zip
|
||||
10
.github/workflows/update_protobufs.yml
vendored
10
.github/workflows/update_protobufs.yml
vendored
@@ -13,13 +13,13 @@ jobs:
|
||||
|
||||
- name: Update submodule
|
||||
run: |
|
||||
git submodule update --remote proto
|
||||
git submodule update --remote protobufs
|
||||
|
||||
- name: Download nanopb
|
||||
run: |
|
||||
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.4-linux-x86.tar.gz
|
||||
tar xvzf nanopb-0.4.4-linux-x86.tar.gz
|
||||
mv nanopb-0.4.4-linux-x86 nanopb-0.4.4
|
||||
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.6-linux-x86.tar.gz
|
||||
tar xvzf nanopb-0.4.6-linux-x86.tar.gz
|
||||
mv nanopb-0.4.6-linux-x86 nanopb-0.4.6
|
||||
|
||||
- name: Re-generate protocol buffers
|
||||
run: |
|
||||
@@ -29,5 +29,5 @@ jobs:
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
add-paths: |
|
||||
proto
|
||||
protobufs
|
||||
src/mesh
|
||||
|
||||
13
.gitmodules
vendored
13
.gitmodules
vendored
@@ -1,9 +1,4 @@
|
||||
[submodule "proto"]
|
||||
path = proto
|
||||
url = https://github.com/meshtastic/Meshtastic-protobufs.git
|
||||
[submodule "sdk-nrfxlib"]
|
||||
path = sdk-nrfxlib
|
||||
url = https://github.com/nrfconnect/sdk-nrfxlib.git
|
||||
[submodule "design"]
|
||||
path = design
|
||||
url = https://github.com/meshtastic/meshtastic-design.git
|
||||
[submodule "protobufs"]
|
||||
path = protobufs
|
||||
url = https://github.com/meshtastic/protobufs.git
|
||||
branch = develop
|
||||
|
||||
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
@@ -51,7 +51,10 @@
|
||||
"iterator": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"iostream": "cpp",
|
||||
"esp_nimble_hci.h": "c"
|
||||
"esp_nimble_hci.h": "c",
|
||||
"map": "cpp",
|
||||
"random": "cpp",
|
||||
"*.tpp": "cpp"
|
||||
},
|
||||
"cSpell.words": [
|
||||
"Blox",
|
||||
@@ -73,10 +76,5 @@
|
||||
"cmake.configureOnOpen": true,
|
||||
"protoc": {
|
||||
"compile_on_save": false,
|
||||
"compile_all_path": "/home/kevinh/development/meshtastic/meshtastic-esp32/proto",
|
||||
"options": [
|
||||
"--java_out=/tmp",
|
||||
"-I=/home/kevinh/development/meshtastic/meshtastic-esp32/proto"
|
||||
]
|
||||
}
|
||||
}
|
||||
21
Dockerfile
21
Dockerfile
@@ -1,16 +1,15 @@
|
||||
FROM ubuntu
|
||||
MAINTAINER Kevin Hester <kevinh@geeksville.com>
|
||||
|
||||
FROM debian:bullseye-slim AS builder
|
||||
RUN apt-get update
|
||||
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install wget python3 g++ zip python3-venv git vim
|
||||
RUN wget https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py -O get-platformio.py; chmod +x get-platformio.py
|
||||
RUN python3 get-platformio.py
|
||||
RUN git clone https://github.com/meshtastic/Meshtastic-device.git
|
||||
RUN cd Meshtastic-device; git submodule update --init --recursive
|
||||
# only build the simulator
|
||||
RUN sed -i 's/^BOARDS_ESP32.*/BOARDS_ESP32=""/' Meshtastic-device/bin/build-all.sh
|
||||
RUN sed -i 's/^BOARDS_NRF52.*/BOARDS_NRF52=""/' Meshtastic-device/bin/build-all.sh
|
||||
RUN sed -i 's/echo "Building Filesystem.*/exit/' Meshtastic-device/bin/build-all.sh
|
||||
RUN . ~/.platformio/penv/bin/activate; cd Meshtastic-device; ./bin/build-all.sh
|
||||
RUN git clone https://github.com/meshtastic/firmware --recurse-submodules
|
||||
RUN cd firmware
|
||||
RUN chmod +x ./firmware/bin/build-native.sh
|
||||
RUN . ~/.platformio/penv/bin/activate; cd firmware; sh ./bin/build-native.sh
|
||||
|
||||
CMD ["/Meshtastic-device/release/latest/bins/universal/meshtasticd_linux_amd64"]
|
||||
FROM frolvlad/alpine-glibc
|
||||
WORKDIR /root/
|
||||
COPY --from=builder /firmware/release/meshtasticd_linux_amd64 ./
|
||||
RUN apk --update add --no-cache g++
|
||||
CMD sh -cx "./meshtasticd_linux_amd64 --hwid '$RANDOM'"
|
||||
24
README.md
24
README.md
@@ -1,18 +1,18 @@
|
||||
# Meshtastic-device
|
||||
[](https://open.vscode.dev/meshtastic/Meshtastic-device)
|
||||
[](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml)
|
||||

|
||||
# Meshtastic Firmware
|
||||
|
||||
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project.
|
||||

|
||||
[](https://github.com/meshtastic/firmware/actions/workflows/main_matrix.yml)
|
||||
[](https://cla-assistant.io/meshtastic/firmware)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
Update Instructions
|
||||
## Overview
|
||||
|
||||
[Using Meshtastic Flasher](https://meshtastic.org/docs/getting-started/meshtastic-flasher)
|
||||
This repository contains the device firmware for the Meshtastic project.
|
||||
|
||||
Manual Method
|
||||
**[Building Instructions](https://meshtastic.org/docs/developers/Firmware/build)**
|
||||
**[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)**
|
||||
|
||||
[For ESP32 devices click here](https://meshtastic.org/docs/getting-started/flashing-esp32)
|
||||
## Stats
|
||||
|
||||
[For nRF52 devices click here](https://meshtastic.org/docs/getting-started/flashing-nrf52)
|
||||
|
||||
For developer information and specific building instructions, please see the [developer documentation](https://meshtastic.org/docs/developers)
|
||||

|
||||
|
||||
52
arch/esp32/esp32.ini
Normal file
52
arch/esp32/esp32.ini
Normal file
@@ -0,0 +1,52 @@
|
||||
; Common settings for ESP targes, mixin with extends = esp32_base
|
||||
[esp32_base]
|
||||
extends = arduino_base
|
||||
platform = platformio/espressif32@^5.2.0
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
|
||||
upload_speed = 921600
|
||||
debug_init_break = tbreak setup
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.filesystem = littlefs
|
||||
|
||||
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
|
||||
# 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
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#657509856ce97e9dddeffb89a559f544faefd5cd
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
|
||||
lib_ignore =
|
||||
segger_rtt
|
||||
ESP32 BLE Arduino
|
||||
|
||||
; leave this commented out to avoid breaking Windows
|
||||
;upload_port = /dev/ttyUSB0
|
||||
;monitor_port = /dev/ttyUSB0
|
||||
|
||||
; Please don't delete these lines. JM uses them.
|
||||
;upload_port = /dev/cu.SLAB_USBtoUART
|
||||
;monitor_port = /dev/cu.SLAB_USBtoUART
|
||||
|
||||
; customize the partition table
|
||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||
board_build.partitions = partition-table.csv
|
||||
45
arch/esp32/esp32s3.ini
Normal file
45
arch/esp32/esp32s3.ini
Normal file
@@ -0,0 +1,45 @@
|
||||
[esp32s3_base]
|
||||
extends = arduino_base
|
||||
platform = platformio/espressif32@^5.2.0
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
|
||||
upload_speed = 961200
|
||||
monitor_speed = 115200
|
||||
debug_init_break = tbreak setup
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.filesystem = littlefs
|
||||
|
||||
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
|
||||
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
|
||||
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-Wall
|
||||
-Wextra
|
||||
-Isrc/platform/esp32
|
||||
-std=c++11
|
||||
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG
|
||||
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
|
||||
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
|
||||
-DAXP_DEBUG_PORT=Serial
|
||||
-DCONFIG_BT_NIMBLE_ENABLED
|
||||
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
|
||||
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
|
||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#657509856ce97e9dddeffb89a559f544faefd5cd
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
|
||||
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
|
||||
|
||||
18
arch/nrf52/nrf52.ini
Normal file
18
arch/nrf52/nrf52.ini
Normal file
@@ -0,0 +1,18 @@
|
||||
[nrf52_base]
|
||||
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
||||
platform = platformio/nordicnrf52@^9.4.0
|
||||
|
||||
extends = arduino_base
|
||||
build_type = debug ; I'm debugging with ICE a lot now
|
||||
build_flags =
|
||||
${arduino_base.build_flags} -Wno-unused-variable
|
||||
-Isrc/platform/nrf52
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/rp2040> -<mesh/eth/>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:feather_nrf52832]
|
||||
extends = nrf52_base
|
||||
board = adafruit_feather_nrf52832
|
||||
14
arch/nrf52/nrf52840.ini
Normal file
14
arch/nrf52/nrf52840.ini
Normal file
@@ -0,0 +1,14 @@
|
||||
[nrf52840_base]
|
||||
extends = nrf52_base
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/Kongduino/Adafruit_nRFCrypto.git#e31a8825ea3300b163a0a3c1ddd5de34e10e1371
|
||||
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:nrf52840dk]
|
||||
extends = nrf52840_base
|
||||
board = nrf52840_dk
|
||||
|
||||
|
||||
20
arch/portduino/portduino.ini
Normal file
20
arch/portduino/portduino.ini
Normal file
@@ -0,0 +1,20 @@
|
||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||
[portduino_base]
|
||||
build_src_filter =
|
||||
${env.build_src_filter}
|
||||
-<platform/esp32/>
|
||||
-<nimble/>
|
||||
-<platform/nrf52/>
|
||||
-<platform/stm32wl/>
|
||||
-<platform/rp2040>
|
||||
-<mesh/http/>
|
||||
-<mesh/eth/>
|
||||
-<modules/esp32>
|
||||
-<modules/Telemetry>
|
||||
+<../variants/portduino>
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
rweather/Crypto@^0.4.0
|
||||
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
|
||||
build_flags = ${arduino_base.build_flags} -Isrc/platform/portduino
|
||||
19
arch/rp2040/rp2040.ini
Normal file
19
arch/rp2040/rp2040.ini
Normal file
@@ -0,0 +1,19 @@
|
||||
; Common settings for rp2040 Processor based targets
|
||||
[rp2040_base]
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5ce1a228e7cae453f366deb8962252b9b7356bbc
|
||||
extends = arduino_base
|
||||
board_build.core = earlephilhower
|
||||
board_build.filesystem_size = 0.5m
|
||||
build_flags =
|
||||
${arduino_base.build_flags} -Wno-unused-variable
|
||||
-Isrc/platform/rp2040
|
||||
-D__PLAT_RP2040__
|
||||
# -D _POSIX_THREADS
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
||||
18
arch/stm32/stm32wl5e.ini
Normal file
18
arch/stm32/stm32wl5e.ini
Normal file
@@ -0,0 +1,18 @@
|
||||
[stm32wl5e_base]
|
||||
platform = platformio/ststm32@^15.4.1
|
||||
board = generic_wl5e
|
||||
framework = arduino
|
||||
build_type = debug
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-Isrc/platform/stm32wl -g
|
||||
-DHAL_SUBGHZ_MODULE_ENABLED
|
||||
# Arduino/PlatformIO framework-arduinoststm32 package does not presently have SUBGHZSPI support
|
||||
# -DPIN_SPI_MOSI=PINSUBGHZSPIMOSI -DPIN_SPI_MISO=PINSUBGHZSPIMISO -DPIN_SPI_SCK=PINSUBGHZSPISCK
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<mqtt/> -<graphics> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
||||
lib_ignore =
|
||||
mathertel/OneButton@^2.0.3
|
||||
BIN
bin/Meshtastic_nRF52_factory_erase.uf2
Normal file
BIN
bin/Meshtastic_nRF52_factory_erase.uf2
Normal file
Binary file not shown.
109
bin/build-all.sh
109
bin/build-all.sh
@@ -1,109 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
SHORT_VERSION=`bin/buildinfo.py short`
|
||||
|
||||
BOARDS_ESP32="rak11200 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"
|
||||
#BOARDS_ESP32=tbeam
|
||||
|
||||
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
|
||||
BOARDS_NRF52="rak4631_5005 rak4631_5005_eink rak4631_19003 t-echo"
|
||||
#BOARDS_NRF52=""
|
||||
|
||||
OUTDIR=release/latest
|
||||
|
||||
# We keep all old builds (and their map files in the archive dir)
|
||||
ARCHIVEDIR=release/archive
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
|
||||
mkdir -p $OUTDIR/bins $ARCHIVEDIR
|
||||
rm -r $OUTDIR/bins/* || true
|
||||
mkdir -p $OUTDIR/bins/universal $OUTDIR/elfs/universal
|
||||
|
||||
# build the named environment and copy the bins to the release directory
|
||||
function do_build() {
|
||||
BOARD=$1
|
||||
isNrf=$3
|
||||
|
||||
echo "Building for $BOARD ($isNrf) with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$BOARD/firmware.*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
basename=universal/firmware-$BOARD-$VERSION
|
||||
|
||||
pio run --environment $BOARD # -v
|
||||
SRCELF=.pio/build/$BOARD/firmware.elf
|
||||
cp $SRCELF $OUTDIR/elfs/$basename.elf
|
||||
|
||||
if [ "$isNrf" = "false" ]
|
||||
then
|
||||
echo "Copying ESP32 bin file"
|
||||
SRCBIN=.pio/build/$BOARD/firmware.bin
|
||||
cp $SRCBIN $OUTDIR/bins/$basename.bin
|
||||
else
|
||||
echo "Generating NRF52 uf2 file"
|
||||
SRCHEX=.pio/build/$BOARD/firmware.hex
|
||||
bin/uf2conv.py $SRCHEX -c -o $OUTDIR/bins/$basename.uf2 -f 0xADA52840
|
||||
fi
|
||||
}
|
||||
|
||||
function do_boards() {
|
||||
declare boards=$1
|
||||
declare isNrf=$2
|
||||
for board in $boards; do
|
||||
# Build universal
|
||||
echo "about to build $board $isNrf"
|
||||
do_build $board "" "$isNrf"
|
||||
done
|
||||
}
|
||||
|
||||
# Make sure our submodules are current
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio lib update
|
||||
|
||||
do_boards "$BOARDS_ESP32" "false"
|
||||
do_boards "$BOARDS_NRF52" "true"
|
||||
|
||||
pio run --environment native
|
||||
cp .pio/build/native/program $OUTDIR/bins/universal/meshtasticd_linux_amd64
|
||||
|
||||
echo "Building Filesystem for ESP32 targets"
|
||||
pio run --environment tbeam -t buildfs
|
||||
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/littlefs-$VERSION.bin
|
||||
|
||||
# keep the bins in archive also
|
||||
cp $OUTDIR/bins/universal/littlefs* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
|
||||
|
||||
echo Updating android bins $OUTDIR/forandroid
|
||||
rm -rf $OUTDIR/forandroid
|
||||
mkdir -p $OUTDIR/forandroid
|
||||
cp -a $OUTDIR/bins/universal/*.bin $OUTDIR/forandroid/
|
||||
|
||||
cat >$OUTDIR/curfirmwareversion.xml <<XML
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- This file is kept in source control because it reflects the last stable
|
||||
release. It is used by the android app for forcing software updates. Do not edit.
|
||||
Generated by bin/buildall.sh -->
|
||||
|
||||
<resources>
|
||||
<string name="cur_firmware_version" translatable="false">$VERSION</string>
|
||||
<string name="short_firmware_version" translatable="false">$SHORT_VERSION</string>
|
||||
</resources>
|
||||
XML
|
||||
|
||||
echo Generating $ARCHIVEDIR/firmware-$VERSION.zip
|
||||
rm -f $ARCHIVEDIR/firmware-$VERSION.zip
|
||||
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/littlefs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* $OUTDIR/bins/universal/meshtasticd* images/system-info.bin bin/device-install.* bin/device-update.*
|
||||
echo Generating $ARCHIVEDIR/elfs-$VERSION.zip
|
||||
rm -f $ARCHIVEDIR/elfs-$VERSION.zip
|
||||
zip --junk-paths $ARCHIVEDIR/elfs-$VERSION.zip $OUTDIR/elfs/universal/firmware-*-$VERSION.*
|
||||
|
||||
echo BUILT ALL
|
||||
@@ -14,7 +14,7 @@ rm -r $OUTDIR/* || true
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio lib update
|
||||
platformio pkg update
|
||||
|
||||
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$1/firmware.*
|
||||
@@ -29,13 +29,11 @@ SRCELF=.pio/build/$1/firmware.elf
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying ESP32 bin file"
|
||||
SRCBIN=.pio/build/$1/firmware.bin
|
||||
SRCBIN=.pio/build/$1/firmware.factory.bin
|
||||
cp $SRCBIN $OUTDIR/$basename.bin
|
||||
|
||||
echo "Building Filesystem for ESP32 targets"
|
||||
pio run --environment tbeam -t buildfs
|
||||
cp .pio/build/tbeam/spiffs.bin $OUTDIR/littlefs-$VERSION.bin
|
||||
cp images/system-info.bin $OUTDIR/system-info.bin
|
||||
|
||||
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
|
||||
@@ -16,7 +16,7 @@ rm -r $OUTDIR/* || true
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio lib update
|
||||
platformio pkg update
|
||||
|
||||
pio run --environment native
|
||||
cp .pio/build/native/program $OUTDIR/meshtasticd_linux_amd64
|
||||
|
||||
@@ -14,7 +14,7 @@ rm -r $OUTDIR/* || true
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio lib update
|
||||
platformio pkg update
|
||||
|
||||
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$1/firmware.*
|
||||
@@ -26,7 +26,9 @@ basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
SRCELF=.pio/build/$1/firmware.elf
|
||||
DFUPKG=.pio/build/$1/firmware.zip
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
cp $DFUPKG $OUTDIR/$basename-ota.zip
|
||||
|
||||
echo "Generating NRF52 uf2 file"
|
||||
SRCHEX=.pio/build/$1/firmware.hex
|
||||
@@ -34,3 +36,4 @@ bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840
|
||||
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
cp bin/*.uf2 $OUTDIR
|
||||
|
||||
36
bin/build-rpi2040.sh
Executable file
36
bin/build-rpi2040.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
SHORT_VERSION=`bin/buildinfo.py short`
|
||||
|
||||
OUTDIR=release/
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
|
||||
# Make sure our submodules are current
|
||||
git submodule update
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
platformio pkg update
|
||||
|
||||
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$1/firmware.*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
SRCELF=.pio/build/$1/firmware.elf
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying uf2 file"
|
||||
SRCBIN=.pio/build/$1/firmware.uf2
|
||||
cp $SRCBIN $OUTDIR/$basename.uf2
|
||||
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
16
bin/bump_version.py
Executable file
16
bin/bump_version.py
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
"""Bump the version number"""
|
||||
|
||||
lines = None
|
||||
|
||||
with open('version.properties', 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
with open('version.properties', 'w', encoding='utf-8') as f:
|
||||
for line in lines:
|
||||
if line.lstrip().startswith("build = "):
|
||||
words = line.split(" = ")
|
||||
ver = f'build = {int(words[1]) + 1}'
|
||||
f.write(f'{ver}\n')
|
||||
else:
|
||||
f.write(line)
|
||||
@@ -13,7 +13,7 @@ if [[ $# -gt 0 ]]; then
|
||||
# can override which environment by passing arg
|
||||
BOARDS="$@"
|
||||
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_5005 rak4631_19003 rak11200 t-echo"
|
||||
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
|
||||
|
||||
echo "BOARDS:${BOARDS}"
|
||||
|
||||
23
bin/check-dependencies.sh
Normal file
23
bin/check-dependencies.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Note: This is a prototype for how we could add static code analysis to the CI.
|
||||
|
||||
set -e
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
# can override which environment by passing arg
|
||||
BOARDS="$@"
|
||||
else
|
||||
BOARDS="rak4631 rak4631_eink t-echo pca10059_diy_eink pico rak11200 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 nano-g1 station-g1 m5stack-core m5stack-coreink tbeam-s3-core"
|
||||
fi
|
||||
|
||||
echo "BOARDS:${BOARDS}"
|
||||
|
||||
CHECK=""
|
||||
for BOARD in $BOARDS; do
|
||||
CHECK="${CHECK} -e ${BOARD}"
|
||||
done
|
||||
|
||||
echo $CHECK
|
||||
|
||||
pio pkg outdated -e $CHECK
|
||||
10
bin/device-install.bat
Normal file → Executable file
10
bin/device-install.bat
Normal file → Executable file
@@ -28,15 +28,15 @@ IF "__%FILENAME%__" == "____" (
|
||||
)
|
||||
IF EXIST %FILENAME% (
|
||||
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
|
||||
%PYTHON% -m esptool --baud 921600 erase_flash
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x1000 system-info.bin
|
||||
%PYTHON% -m esptool --baud 115200 erase_flash
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
||||
for %%f in (littlefs-*.bin) do (
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x00390000 %%f
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
|
||||
)
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x10000 %FILENAME%
|
||||
) else (
|
||||
echo "Invalid file: %FILENAME%"
|
||||
goto HELP
|
||||
)
|
||||
|
||||
:EOF
|
||||
:EOF
|
||||
|
||||
@@ -47,9 +47,10 @@ shift "$((OPTIND-1))"
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||
"$PYTHON" -m esptool erase_flash
|
||||
"$PYTHON" -m esptool write_flash 0x1000 system-info.bin
|
||||
"$PYTHON" -m esptool write_flash 0x00390000 littlefs-*.bin
|
||||
"$PYTHON" -m esptool write_flash 0x10000 ${FILENAME}
|
||||
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
||||
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
|
||||
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
|
||||
6
bin/device-update.bat
Normal file → Executable file
6
bin/device-update.bat
Normal file → Executable file
@@ -28,12 +28,10 @@ IF "__%FILENAME%__" == "____" (
|
||||
)
|
||||
IF EXIST %FILENAME% (
|
||||
echo Trying to flash update %FILENAME%
|
||||
%PYTHON% -m esptool --baud 921600 write_flash 0x10000 %FILENAME%
|
||||
echo Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used
|
||||
%PYTHON% -m esptool --baud 921600 erase_region 0xe000 0x2000
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||
) else (
|
||||
echo "Invalid file: %FILENAME%"
|
||||
goto HELP
|
||||
)
|
||||
|
||||
:EOF
|
||||
:EOF
|
||||
|
||||
@@ -44,9 +44,7 @@ shift "$((OPTIND-1))"
|
||||
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
echo "Trying to flash update ${FILENAME}."
|
||||
$PYTHON -m esptool --baud 921600 write_flash 0x10000 ${FILENAME}
|
||||
echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used"
|
||||
$PYTHON -m esptool --baud 921600 erase_region 0xe000 0x2000
|
||||
$PYTHON -m esptool --baud 115200 write_flash 0x00 ${FILENAME}
|
||||
else
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
show_help
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import getopt
|
||||
import sys
|
||||
import os
|
||||
from littlefs import LittleFS
|
||||
from pathlib import Path
|
||||
|
||||
print( "Building LittleFS image..." )
|
||||
|
||||
argList = sys.argv[1:]
|
||||
arxx = { argList[i]: argList[i+1] for i in range(0, len(argList)-1, 2) }
|
||||
|
||||
dataPath = arxx["-c"]
|
||||
blockSize = int(arxx["-b"])
|
||||
blockCount = int(arxx["-s"]) / blockSize
|
||||
|
||||
cwd = os.getcwd()
|
||||
|
||||
os.chdir(dataPath)
|
||||
|
||||
fileList = []
|
||||
dirList = []
|
||||
|
||||
for (dirpath, dirnames, filenames) in os.walk('.'):
|
||||
for f in filenames:
|
||||
if (f[:1] != '.'):
|
||||
fileList.append( os.path.join(dirpath, f) )
|
||||
for d in dirnames:
|
||||
if (d[:1] != '.'):
|
||||
dirList.append( os.path.join(dirpath, d) )
|
||||
|
||||
fs = LittleFS(block_size=blockSize, block_count=blockCount) # create a 448kB partition
|
||||
|
||||
for curDir in dirList:
|
||||
print( "Creating dir " + curDir )
|
||||
fs.mkdir( curDir )
|
||||
|
||||
for curFile in fileList:
|
||||
print( "Adding file " + curFile )
|
||||
with open( curFile, 'rb' ) as f:
|
||||
data = f.read()
|
||||
|
||||
with fs.open( curFile, 'wb') as fh:
|
||||
fh.write( data )
|
||||
|
||||
outName = argList[-1]
|
||||
|
||||
os.chdir(cwd)
|
||||
|
||||
with open(outName, 'wb') as fh:
|
||||
fh.write(fs.context.buffer)
|
||||
@@ -1,24 +1,70 @@
|
||||
|
||||
|
||||
import subprocess
|
||||
import configparser
|
||||
import traceback
|
||||
import sys
|
||||
from os.path import join
|
||||
from readprops import readProps
|
||||
|
||||
Import("env")
|
||||
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/bin/mklittlefs.py' )
|
||||
try:
|
||||
import littlefs
|
||||
except ImportError:
|
||||
env.Execute("$PYTHONEXE -m pip install littlefs-python")
|
||||
platform = env.PioPlatform()
|
||||
|
||||
def esp32_create_combined_bin(source, target, env):
|
||||
# this sub is borrowed from ESPEasy build toolchain. It's licensed under GPL V3
|
||||
# https://github.com/letscontrolit/ESPEasy/blob/mega/tools/pio/post_esp32.py
|
||||
print("Generating combined binary for serial flashing")
|
||||
|
||||
app_offset = 0x10000
|
||||
|
||||
new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin")
|
||||
sections = env.subst(env.get("FLASH_EXTRA_IMAGES"))
|
||||
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
|
||||
chip = env.get("BOARD_MCU")
|
||||
flash_size = env.BoardConfig().get("upload.flash_size")
|
||||
flash_freq = env.BoardConfig().get("build.f_flash", '40m')
|
||||
flash_freq = flash_freq.replace('000000L', 'm')
|
||||
flash_mode = env.BoardConfig().get("build.flash_mode", "dio")
|
||||
memory_type = env.BoardConfig().get("build.arduino.memory_type", "qio_qspi")
|
||||
if flash_mode == "qio" or flash_mode == "qout":
|
||||
flash_mode = "dio"
|
||||
if memory_type == "opi_opi" or memory_type == "opi_qspi":
|
||||
flash_mode = "dout"
|
||||
cmd = [
|
||||
"--chip",
|
||||
chip,
|
||||
"merge_bin",
|
||||
"-o",
|
||||
new_file_name,
|
||||
"--flash_mode",
|
||||
flash_mode,
|
||||
"--flash_freq",
|
||||
flash_freq,
|
||||
"--flash_size",
|
||||
flash_size,
|
||||
]
|
||||
|
||||
print(" Offset | File")
|
||||
for section in sections:
|
||||
sect_adr, sect_file = section.split(" ", 1)
|
||||
print(f" - {sect_adr} | {sect_file}")
|
||||
cmd += [sect_adr, sect_file]
|
||||
|
||||
print(f" - {hex(app_offset)} | {firmware_name}")
|
||||
cmd += [hex(app_offset), firmware_name]
|
||||
|
||||
print('Using esptool.py arguments: %s' % ' '.join(cmd))
|
||||
|
||||
esptool.main(cmd)
|
||||
|
||||
if (platform.name == "espressif32"):
|
||||
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
||||
import esptool
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin)
|
||||
|
||||
Import("projenv")
|
||||
|
||||
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
|
||||
verObj = readProps(prefsLoc)
|
||||
print("Using meshtastic platform-custom.py, firmare version " + verObj['long'])
|
||||
# print("path is" + ','.join(sys.path))
|
||||
print("Using meshtastic platformio-custom.py, firmware version " + verObj['long'])
|
||||
|
||||
# General options that are passed to the C and C++ compilers
|
||||
projenv.Append(CCFLAGS=[
|
||||
|
||||
@@ -9,9 +9,6 @@ VERSION=`bin/buildinfo.py long`
|
||||
# Must have a V prefix to trigger github
|
||||
git tag "v${VERSION}"
|
||||
|
||||
# Commented out per https://github.com/meshtastic/Meshtastic-device/issues/947
|
||||
#git push root "v${VERSION}" # push the tag
|
||||
|
||||
git push origin "v${VERSION}" # push the tag
|
||||
|
||||
echo "Tag ${VERSION} pushed to github, github actions should now be building the draft release. If it seems good, click to publish it"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
esptool.py --baud 921600 read_flash 0x1000 0xf000 system-info.img
|
||||
esptool.py --baud 115200 read_flash 0x1000 0xf000 system-info.img
|
||||
|
||||
@@ -32,6 +32,6 @@ def readProps(prefsLoc):
|
||||
# traceback.print_exc()
|
||||
verObj['long'] = verObj['short']
|
||||
|
||||
# print("firmare version " + verStr)
|
||||
# print("firmware version " + verStr)
|
||||
return verObj
|
||||
# print("path is" + ','.join(sys.path))
|
||||
|
||||
@@ -1 +1 @@
|
||||
cd proto && ..\nanopb-0.4.5\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\proto *.proto
|
||||
cd protobufs && ..\nanopb-0.4.6\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs *.proto
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
set -e
|
||||
|
||||
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.5 to be located in the"
|
||||
echo "meshtastic-device root directory if the following step fails, you should download the correct"
|
||||
echo "prebuilt binaries for your computer into nanopb-0.4.5"
|
||||
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.6 to be located in the"
|
||||
echo "firmware root directory if the following step fails, you should download the correct"
|
||||
echo "prebuilt binaries for your computer into nanopb-0.4.6"
|
||||
|
||||
# the nanopb tool seems to require that the .options file be in the current directory!
|
||||
cd proto
|
||||
../nanopb-0.4.5/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../proto *.proto
|
||||
cd protobufs
|
||||
../nanopb-0.4.6/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../protobufs *.proto
|
||||
|
||||
#echo "Regenerating protobuf documentation - if you see an error message"
|
||||
#echo "you can ignore it unless doing a new protobuf release to github."
|
||||
|
||||
31
boards/generic_wl5e.json
Normal file
31
boards/generic_wl5e.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"build": {
|
||||
"core": "stm32",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_GENERIC_WLE5CCUX",
|
||||
"f_cpu": "48000000L",
|
||||
"mcu": "stm32wle5ccu",
|
||||
"variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U",
|
||||
"product_line": "STM32WLE5xx"
|
||||
},
|
||||
"debug": {
|
||||
"default_tools": [
|
||||
"stlink"
|
||||
],
|
||||
"jlink_device": "STM32WLE5CC",
|
||||
"openocd_target": "stm32wlx",
|
||||
"svd_path": "STM32WLE5_CM4.svd"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "BB-STM32WL",
|
||||
"upload": {
|
||||
"maximum_ram_size": 65536,
|
||||
"maximum_size": 262144,
|
||||
"protocol": "cmsis-dap",
|
||||
"protocols": [
|
||||
"cmsis-dap"
|
||||
]
|
||||
},
|
||||
"url": "https://www.st.com/en/microcontrollers-microprocessors/stm32wl-series.html",
|
||||
"vendor": "ST"
|
||||
}
|
||||
72
boards/nordic_pca10059.json
Normal file
72
boards/nordic_pca10059.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"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": "PCA10059",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "nRF52840 Dongle",
|
||||
"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": "nRF52840 Dongle",
|
||||
"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://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle",
|
||||
"vendor": "Nordic Semiconductor"
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino":{
|
||||
"ldscript": "nrf52832_s132_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DNRF52832_XXAA -DNRF52",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x10c4",
|
||||
"0xea60"
|
||||
]
|
||||
],
|
||||
"usb_product": "RAK815",
|
||||
"mcu": "nrf52832",
|
||||
"variant": "rak815",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS132",
|
||||
"sd_name": "s132",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B7"
|
||||
}
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth"
|
||||
],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52832_xxAA",
|
||||
"svd_path": "nrf52.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "RAK RAK815",
|
||||
"upload": {
|
||||
"maximum_ram_size": 65536,
|
||||
"maximum_size": 524288,
|
||||
"require_upload_port": true,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"nrfutil",
|
||||
"stlink"
|
||||
]
|
||||
},
|
||||
"url": "https://store.rakwireless.com/products/rak815-hybrid-location-tracker",
|
||||
"vendor": "RAK"
|
||||
}
|
||||
48
boards/tbeam-s3-core.json
Normal file
48
boards/tbeam-s3-core.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino":{
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DLILYGO_TBEAM_S3_CORE",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_DFU_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MSC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "dio",
|
||||
"hwids": [
|
||||
[
|
||||
"0X303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "tbeam-s3-core"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "LilyGo TBeam-S3-Core",
|
||||
"upload": {
|
||||
"flash_size": "8MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "http://www.lilygo.cn/",
|
||||
"vendor": "LilyGo"
|
||||
}
|
||||
1
design
1
design
Submodule design deleted from 73ba05ceef
13
docker-compose.yml
Normal file
13
docker-compose.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
version: "3.7"
|
||||
|
||||
services:
|
||||
meshtastic-node:
|
||||
build: .
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 80
|
||||
networks:
|
||||
- mesh
|
||||
|
||||
networks:
|
||||
mesh:
|
||||
Binary file not shown.
@@ -1,8 +1,8 @@
|
||||
# FIXME! using the genpartitions based table doesn't work on TTGO so for now I stay with my old memory map
|
||||
# This is a layout for 4MB of flash
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x1c0000,
|
||||
app1, app, ota_1, 0x1d0000,0x1c0000,
|
||||
spiffs, data, spiffs, 0x390000,0x070000,
|
||||
nvs, data, nvs, 0x009000, 0x005000,
|
||||
otadata, data, ota, 0x00e000, 0x002000,
|
||||
app, app, ota_0, 0x010000, 0x250000,
|
||||
flashApp, app, ota_1, 0x260000, 0x0A0000,
|
||||
spiffs, data, spiffs, 0x300000, 0x100000,
|
||||
|
151
platformio.ini
151
platformio.ini
@@ -2,7 +2,9 @@
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = tbeam
|
||||
;default_envs = tbeam
|
||||
;default_envs = pico
|
||||
;default_envs = tbeam-s3-core
|
||||
;default_envs = tbeam0.7
|
||||
;default_envs = heltec-v1
|
||||
;default_envs = heltec-v2.0
|
||||
@@ -16,13 +18,17 @@ default_envs = tbeam
|
||||
;default_envs = t-echo
|
||||
;default_envs = nrf52840dk-geeksville
|
||||
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||
;default_envs = rak4631_5005
|
||||
;default_envs = rak4631_5005_eink
|
||||
;default_envs = rak4631_19003
|
||||
;default_envs = nano-g1
|
||||
;default_envs = pca10059_diy_eink
|
||||
;default_envs = meshtastic-diy-v1
|
||||
;default_envs = meshtastic-diy-v1.1
|
||||
;default_envs = meshtastic-dr-dev
|
||||
;default_envs = m5stack-coreink
|
||||
;default_envs = rak4631
|
||||
|
||||
extra_configs = variants/*/platformio.ini
|
||||
extra_configs =
|
||||
arch/*/*.ini
|
||||
variants/*/platformio.ini
|
||||
|
||||
[env]
|
||||
extra_scripts = bin/platformio-custom.py
|
||||
@@ -36,125 +42,58 @@ build_flags = -Wno-missing-field-initializers
|
||||
-Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
|
||||
-DUSE_THREAD_NAMES
|
||||
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
-DPB_ENABLE_MALLOC=1
|
||||
|
||||
monitor_speed = 921600
|
||||
monitor_speed = 115200
|
||||
|
||||
lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#53580644255b48ebb7a737343c6b4e71c7e11cf2 ; ESP8266_SSD1306
|
||||
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
|
||||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||
https://github.com/meshtastic/arduino-fsm.git
|
||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
||||
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
|
||||
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||
SPI
|
||||
https://github.com/geeksville/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
PubSubClient
|
||||
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#2f0d0528d737000043e949f4c3bdfb623cf0b902
|
||||
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
nanopb/Nanopb@^0.4.6
|
||||
meshtastic/json11@^1.0.2
|
||||
erriez/ErriezCRC32@^1.0.1
|
||||
|
||||
; Used for the code analysis in PIO Home / Inspect
|
||||
check_tool = cppcheck
|
||||
check_skip_packages = yes
|
||||
check_flags =
|
||||
-DAPP_VERSION=1.0.0
|
||||
--suppressions-list=suppressions.txt
|
||||
|
||||
; Common settings for conventional (non Portduino) Arduino targets
|
||||
[arduino_base]
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
build_flags = ${env.build_flags} -Os
|
||||
# -DRADIOLIB_GODMODE
|
||||
src_filter = ${env.src_filter} -<portduino/>
|
||||
; Portduino is using meshtastic fork for now
|
||||
jgromes/RadioLib@5.4.1
|
||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
|
||||
|
||||
; Common libs for environmental measurements (not included in native / portduino)
|
||||
[environmental]
|
||||
build_flags = ${env.build_flags} -Os
|
||||
-DRADIOLIB_SPI_PARANOID=0
|
||||
# -DRADIOLIB_GODMODE
|
||||
build_src_filter = ${env.build_src_filter} -<platform/portduino/>
|
||||
|
||||
; Common libs for communicating over TCP/IP networks such as MQTT
|
||||
[networking_base]
|
||||
lib_deps =
|
||||
adafruit/DHT sensor library@^1.4.1
|
||||
knolleary/PubSubClient@^2.8
|
||||
arduino-libraries/NTPClient@^3.1.0
|
||||
meshtastic/json11@^1.0.2
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
; (not included in native / portduino)
|
||||
[environmental_base]
|
||||
lib_deps =
|
||||
adafruit/Adafruit BusIO@^1.11.4
|
||||
adafruit/Adafruit Unified Sensor@^1.1.4
|
||||
paulstoffregen/OneWire@^2.3.5
|
||||
robtillaart/DS18B20@^0.1.11
|
||||
adafruit/Adafruit BMP280 Library@^2.6.6
|
||||
adafruit/Adafruit BME280 Library@^2.2.2
|
||||
adafruit/Adafruit BME680 Library@^2.0.1
|
||||
adafruit/Adafruit MCP9808 Library@^2.0.0
|
||||
|
||||
; Common settings for ESP targes, mixin with extends = esp32_base
|
||||
[esp32_base]
|
||||
extends = arduino_base
|
||||
platform = espressif32
|
||||
src_filter =
|
||||
${arduino_base.src_filter} -<nrf52/>
|
||||
upload_speed = 921600
|
||||
debug_init_break = tbreak setup
|
||||
# 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
|
||||
# -DUSE_NEW_ESP32_BLUETOOTH will enable the new NimBLE C++ api
|
||||
build_flags =
|
||||
${arduino_base.build_flags} -Wall -Wextra -Isrc/esp32 -Isrc/esp32-mfix-esp32-psram-cache-issue -lnimble -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 -DUSE_NEW_ESP32_BLUETOOTH
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git
|
||||
h2zero/NimBLE-Arduino@1.3.7
|
||||
tobozo/ESP32-targz@^1.1.4
|
||||
arduino-libraries/NTPClient@^3.1.0
|
||||
lorol/LittleFS_esp32@^1.0.6
|
||||
lib_ignore =
|
||||
segger_rtt
|
||||
ESP32 BLE Arduino
|
||||
platform_packages =
|
||||
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#4cde0f5d412d2695184f32e8a47e9bea57b45276
|
||||
; leave this commented out to avoid breaking Windows
|
||||
|
||||
;upload_port = /dev/ttyUSB0
|
||||
;monitor_port = /dev/ttyUSB0
|
||||
|
||||
; customize the partition table
|
||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||
board_build.partitions = partition-table.csv
|
||||
|
||||
[nrf52_base]
|
||||
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
||||
; platform = nordicnrf52 ;pending https://github.com/platformio/builder-framework-arduino-nrf5/pull/7
|
||||
platform = https://github.com/meshtastic/platform-nordicnrf52.git#merge
|
||||
|
||||
extends = arduino_base
|
||||
build_type = debug ; I'm debugging with ICE a lot now
|
||||
; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME)
|
||||
build_flags =
|
||||
${arduino_base.build_flags} -Wno-unused-variable
|
||||
-Isrc/nrf52
|
||||
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
|
||||
src_filter =
|
||||
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/>
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
|
||||
[nrf52840_base]
|
||||
extends = nrf52_base
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental.lib_deps}
|
||||
Adafruit nRFCrypto
|
||||
|
||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||
[env:nrf52840dk]
|
||||
extends = nrf52840_base
|
||||
board = nrf52840_dk
|
||||
|
||||
; 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
|
||||
|
||||
[env:rak815]
|
||||
extends = nrf52_base
|
||||
board = rak815
|
||||
debug_tool = jlink
|
||||
upload_protocol = jlink
|
||||
monitor_speed = 115200
|
||||
adafruit/Adafruit INA260 Library@^1.5.0
|
||||
adafruit/Adafruit INA219@^1.2.0
|
||||
adafruit/Adafruit SHTC3 Library@^1.0.0
|
||||
adafruit/Adafruit LPS2X@^2.0.4
|
||||
1
proto
1
proto
Submodule proto deleted from 31eaff0924
1
protobufs
Submodule
1
protobufs
Submodule
Submodule protobufs added at c82c15aac7
Submodule sdk-nrfxlib deleted from e6e02cb83d
@@ -7,7 +7,7 @@ const uint8_t MESH_SERVICE_UUID_16[16u] = {0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0
|
||||
0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b};
|
||||
const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1,
|
||||
0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7};
|
||||
const uint8_t FROMRADIO_UUID_16[16u] = {0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5,
|
||||
0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b};
|
||||
const uint8_t FROMRADIO_UUID_16[16u] = {0x02, 0x00, 0x12, 0xac, 0x42, 0x02, 0x78, 0xb8,
|
||||
0xed, 0x11, 0x93, 0x49, 0x9e, 0xe6, 0x55, 0x2c};
|
||||
const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6,
|
||||
0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed};
|
||||
@@ -9,7 +9,7 @@
|
||||
#define MESH_SERVICE_UUID "6ba1b218-15a8-461f-9fa8-5dcae273eafd"
|
||||
|
||||
#define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7"
|
||||
#define FROMRADIO_UUID "8ba2bcc2-ee02-4a55-a531-c525c5e454d5"
|
||||
#define FROMRADIO_UUID "2c55e69e-4993-11ed-b878-0242ac120002"
|
||||
#define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453"
|
||||
|
||||
// NRF52 wants these constants as byte arrays
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
#include "configuration.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "buzz.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "power.h"
|
||||
#include "buzz.h"
|
||||
#include <OneButton.h>
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
#endif
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
/**
|
||||
@@ -78,14 +74,9 @@ class ButtonThread : public concurrency::OSThread
|
||||
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(BUTTON_PIN_TOUCH, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButtonTouch.attachClick(touchPressed);
|
||||
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -114,16 +105,17 @@ class ButtonThread : public concurrency::OSThread
|
||||
|
||||
private:
|
||||
static void touchPressed()
|
||||
{
|
||||
{
|
||||
screen->forceDisplay();
|
||||
DEBUG_MSG("touch press!\n");
|
||||
DEBUG_MSG("touch press!\n");
|
||||
}
|
||||
|
||||
|
||||
static void userButtonPressed()
|
||||
{
|
||||
// DEBUG_MSG("press!\n");
|
||||
#ifdef BUTTON_PIN
|
||||
if ((BUTTON_PIN != radioConfig.preferences.inputbroker_pin_press) || !radioConfig.preferences.canned_message_module_enabled) {
|
||||
if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) ||
|
||||
!moduleConfig.canned_message.enabled) {
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
}
|
||||
#endif
|
||||
@@ -131,25 +123,32 @@ class ButtonThread : public concurrency::OSThread
|
||||
static void userButtonPressedLong()
|
||||
{
|
||||
// DEBUG_MSG("Long press!\n");
|
||||
#ifndef NRF52_SERIES
|
||||
#ifdef ARCH_ESP32
|
||||
screen->adjustBrightness();
|
||||
#endif
|
||||
// If user button is held down for 5 seconds, shutdown the device.
|
||||
if (millis() - longPressTime > 5 * 1000) {
|
||||
#ifdef TBEAM_V10
|
||||
if (axp192_found == true) {
|
||||
if ((millis() - longPressTime > 5 * 1000) && (longPressTime > 0)) {
|
||||
#ifdef HAS_PMU
|
||||
if (pmu_found == true) {
|
||||
setLed(false);
|
||||
power->shutdown();
|
||||
}
|
||||
#elif NRF52_SERIES
|
||||
#elif defined(ARCH_NRF52)
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediatedly.
|
||||
if (!shutdown_on_long_stop) {
|
||||
if ((!shutdown_on_long_stop) && (millis() > 30 * 1000)) {
|
||||
screen->startShutdownScreen();
|
||||
DEBUG_MSG("Shutdown from long press");
|
||||
playBeep();
|
||||
#ifdef PIN_LED1
|
||||
ledOff(PIN_LED1);
|
||||
#endif
|
||||
#ifdef PIN_LED2
|
||||
ledOff(PIN_LED2);
|
||||
#endif
|
||||
#ifdef PIN_LED3
|
||||
ledOff(PIN_LED3);
|
||||
#endif
|
||||
shutdown_on_long_stop = true;
|
||||
}
|
||||
#endif
|
||||
@@ -160,40 +159,38 @@ class ButtonThread : public concurrency::OSThread
|
||||
|
||||
static void userButtonDoublePressed()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
disablePin();
|
||||
#elif defined(HAS_EINK)
|
||||
digitalWrite(PIN_EINK_EN,digitalRead(PIN_EINK_EN) == LOW);
|
||||
#if defined(USE_EINK) && defined(PIN_EINK_EN)
|
||||
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void userButtonMultiPressed()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
clearNVS();
|
||||
#endif
|
||||
#ifdef NRF52_SERIES
|
||||
clearBonds();
|
||||
#endif
|
||||
screen->print("Sent ad-hoc ping\n");
|
||||
service.refreshMyNodeInfo();
|
||||
service.sendNetworkPing(NODENUM_BROADCAST, true);
|
||||
}
|
||||
|
||||
|
||||
static void userButtonPressedLongStart()
|
||||
{
|
||||
DEBUG_MSG("Long press start!\n");
|
||||
longPressTime = millis();
|
||||
if (millis() > 30 * 1000) {
|
||||
DEBUG_MSG("Long press start!\n");
|
||||
longPressTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
static void userButtonPressedLongStop()
|
||||
{
|
||||
DEBUG_MSG("Long press stop!\n");
|
||||
longPressTime = 0;
|
||||
if (shutdown_on_long_stop) {
|
||||
playShutdownMelody();
|
||||
delay(3000);
|
||||
power->shutdown();
|
||||
if (millis() > 30 * 1000) {
|
||||
DEBUG_MSG("Long press stop!\n");
|
||||
longPressTime = 0;
|
||||
if (shutdown_on_long_stop) {
|
||||
playShutdownMelody();
|
||||
delay(3000);
|
||||
power->shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace concurrency
|
||||
|
||||
@@ -10,36 +10,13 @@
|
||||
#ifdef CONSOLE_MAX_BAUD
|
||||
#define SERIAL_BAUD CONSOLE_MAX_BAUD
|
||||
#else
|
||||
#define SERIAL_BAUD 921600 // Serial debug baud rate
|
||||
#define SERIAL_BAUD 115200 // Serial debug baud rate
|
||||
#endif
|
||||
|
||||
#include "SerialConsole.h"
|
||||
|
||||
#define DEBUG_PORT (*console) // Serial debug port
|
||||
|
||||
// What platforms should use SEGGER?
|
||||
#ifdef NRF52_SERIES
|
||||
|
||||
// Always include the SEGGER code on NRF52 - because useful for debugging
|
||||
#include "SEGGER_RTT.h"
|
||||
|
||||
// The channel we send stdout data to
|
||||
#define SEGGER_STDOUT_CH 0
|
||||
|
||||
// Debug printing to segger console
|
||||
#define SEGGER_MSG(...) SEGGER_RTT_printf(SEGGER_STDOUT_CH, __VA_ARGS__)
|
||||
|
||||
// If we are not on a NRF52840 (which has built in USB-ACM serial support) and we don't have serial pins hooked up, then we MUST
|
||||
// use SEGGER for debug output
|
||||
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
|
||||
// No serial ports on this board - ONLY use segger in memory console
|
||||
#define USE_SEGGER
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
|
||||
#endif
|
||||
|
||||
#ifdef USE_SEGGER
|
||||
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#else
|
||||
|
||||
144
src/FSCommon.cpp
144
src/FSCommon.cpp
@@ -1,10 +1,58 @@
|
||||
#include "configuration.h"
|
||||
#include "FSCommon.h"
|
||||
|
||||
void listDir(const char * dirname, uint8_t levels)
|
||||
#ifdef FSCom
|
||||
|
||||
bool copyFile(const char* from, const char* to)
|
||||
{
|
||||
File root = FSCom.open(dirname);
|
||||
#ifdef FSCom
|
||||
unsigned char cbuffer[16];
|
||||
|
||||
File f1 = FSCom.open(from, FILE_O_READ);
|
||||
if (!f1){
|
||||
DEBUG_MSG("Failed to open source file %s\n", from);
|
||||
return false;
|
||||
}
|
||||
|
||||
File f2 = FSCom.open(to, FILE_O_WRITE);
|
||||
if (!f2) {
|
||||
DEBUG_MSG("Failed to open destination file %s\n", to);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (f1.available() > 0) {
|
||||
byte i = f1.read(cbuffer, 16);
|
||||
f2.write(cbuffer, i);
|
||||
}
|
||||
|
||||
f2.close();
|
||||
f1.close();
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool renameFile(const char* pathFrom, const char* pathTo)
|
||||
{
|
||||
#ifdef FSCom
|
||||
#ifdef ARCH_ESP32
|
||||
// rename was fixed for ESP32 IDF LittleFS in April
|
||||
return FSCom.rename(pathFrom, pathTo);
|
||||
#else
|
||||
if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom) ) {
|
||||
return true;
|
||||
} else{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void listDir(const char * dirname, uint8_t levels, boolean del = false)
|
||||
{
|
||||
#ifdef FSCom
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
char buffer[255];
|
||||
#endif
|
||||
File root = FSCom.open(dirname, FILE_O_READ);
|
||||
if(!root){
|
||||
return;
|
||||
}
|
||||
@@ -16,15 +64,92 @@ void listDir(const char * dirname, uint8_t levels)
|
||||
while(file){
|
||||
if(file.isDirectory() && !String(file.name()).endsWith(".")) {
|
||||
if(levels){
|
||||
listDir(file.name(), levels -1);
|
||||
#ifdef ARCH_ESP32
|
||||
listDir(file.path(), levels -1, del);
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", file.path());
|
||||
strcpy(buffer, file.path());
|
||||
file.close();
|
||||
FSCom.rmdir(buffer);
|
||||
} else {
|
||||
file.close();
|
||||
}
|
||||
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
listDir(file.name(), levels -1, del);
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", file.name());
|
||||
strcpy(buffer, file.name());
|
||||
file.close();
|
||||
FSCom.rmdir(buffer);
|
||||
} else {
|
||||
file.close();
|
||||
}
|
||||
#else
|
||||
listDir(file.name(), levels -1, del);
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG(" %s (%i Bytes)\n", file.name(), file.size());
|
||||
#ifdef ARCH_ESP32
|
||||
if(del) {
|
||||
DEBUG_MSG("Deleting %s\n", file.path());
|
||||
strcpy(buffer, file.path());
|
||||
file.close();
|
||||
FSCom.remove(buffer);
|
||||
} else {
|
||||
DEBUG_MSG(" %s (%i Bytes)\n", file.path(), file.size());
|
||||
file.close();
|
||||
}
|
||||
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
if(del) {
|
||||
DEBUG_MSG("Deleting %s\n", file.name());
|
||||
strcpy(buffer, file.name());
|
||||
file.close();
|
||||
FSCom.remove(buffer);
|
||||
} else {
|
||||
DEBUG_MSG(" %s (%i Bytes)\n", file.name(), file.size());
|
||||
file.close();
|
||||
}
|
||||
#else
|
||||
DEBUG_MSG(" %s (%i Bytes)\n", file.name(), file.size());
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
file.close();
|
||||
file = root.openNextFile();
|
||||
}
|
||||
file.close();
|
||||
#ifdef ARCH_ESP32
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", root.path());
|
||||
strcpy(buffer, root.path());
|
||||
root.close();
|
||||
FSCom.rmdir(buffer);
|
||||
} else {
|
||||
root.close();
|
||||
}
|
||||
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
if(del) {
|
||||
DEBUG_MSG("Removing %s\n", root.name());
|
||||
strcpy(buffer, root.name());
|
||||
root.close();
|
||||
FSCom.rmdir(buffer);
|
||||
} else {
|
||||
root.close();
|
||||
}
|
||||
#else
|
||||
root.close();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void rmDir(const char * dirname)
|
||||
{
|
||||
#ifdef FSCom
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
listDir(dirname, 10, true);
|
||||
#elif defined(ARCH_NRF52)
|
||||
// nRF52 implementation of LittleFS has a recursive delete function
|
||||
FSCom.rmdir_r(dirname);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -36,8 +161,11 @@ void fsInit()
|
||||
DEBUG_MSG("ERROR filesystem mount Failed. Formatting...\n");
|
||||
assert(0); // FIXME - report failure to phone
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
DEBUG_MSG("Filesystem files (%d/%d Bytes):\n", FSCom.usedBytes(), FSCom.totalBytes());
|
||||
#else
|
||||
DEBUG_MSG("Filesystem files:\n");
|
||||
#endif
|
||||
listDir("/", 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4,21 +4,34 @@
|
||||
|
||||
// Cross platform filesystem API
|
||||
|
||||
#ifdef PORTDUINO
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
// Portduino version
|
||||
#include "PortduinoFS.h"
|
||||
#define FSCom PortduinoFS
|
||||
#define FSBegin() true
|
||||
#define FILE_O_WRITE "w"
|
||||
#define FILE_O_READ "r"
|
||||
#elif !defined(NO_ESP32)
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_RP2040)
|
||||
// RP2040
|
||||
#include "LittleFS.h"
|
||||
#define FSCom LittleFS
|
||||
#define FSBegin() FSCom.begin()
|
||||
#define FILE_O_WRITE "w"
|
||||
#define FILE_O_READ "r"
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_ESP32)
|
||||
// ESP32 version
|
||||
#include "LITTLEFS.h"
|
||||
#define FSCom LITTLEFS
|
||||
#include "LittleFS.h"
|
||||
#define FSCom LittleFS
|
||||
#define FSBegin() FSCom.begin(true)
|
||||
#define FILE_O_WRITE "w"
|
||||
#define FILE_O_READ "r"
|
||||
#else
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_NRF52)
|
||||
// NRF52 version
|
||||
#include "InternalFileSystem.h"
|
||||
#define FSCom InternalFS
|
||||
@@ -26,4 +39,8 @@
|
||||
using namespace Adafruit_LittleFS_Namespace;
|
||||
#endif
|
||||
|
||||
void fsInit();
|
||||
void fsInit();
|
||||
bool copyFile(const char* from, const char* to);
|
||||
bool renameFile(const char* pathFrom, const char* pathTo);
|
||||
void listDir(const char * dirname, uint8_t levels, boolean del);
|
||||
void rmDir(const char * dirname);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "NodeDB.h"
|
||||
#include "Status.h"
|
||||
#include "configuration.h"
|
||||
#include "NodeDB.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
extern NodeDB nodeDB;
|
||||
@@ -17,33 +17,32 @@ class GPSStatus : public Status
|
||||
CallbackObserver<GPSStatus, const GPSStatus *> statusObserver =
|
||||
CallbackObserver<GPSStatus, const GPSStatus *>(this, &GPSStatus::updateStatus);
|
||||
|
||||
bool hasLock = false; // default to false, until we complete our first read
|
||||
bool isConnected = false; // Do we have a GPS we are talking to
|
||||
bool hasLock = false; // default to false, until we complete our first read
|
||||
bool isConnected = false; // Do we have a GPS we are talking to
|
||||
|
||||
Position p = Position_init_default;
|
||||
|
||||
public:
|
||||
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
||||
|
||||
// proposed for deprecation
|
||||
GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
|
||||
uint32_t heading, uint32_t numSatellites)
|
||||
: Status()
|
||||
{
|
||||
this->hasLock = hasLock;
|
||||
this->isConnected = isConnected;
|
||||
// // proposed for deprecation
|
||||
// GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
|
||||
// uint32_t heading, uint32_t numSatellites)
|
||||
// : Status()
|
||||
// {
|
||||
// this->hasLock = hasLock;
|
||||
// this->isConnected = isConnected;
|
||||
|
||||
this->p.latitude_i = latitude;
|
||||
this->p.longitude_i = longitude;
|
||||
this->p.altitude = altitude;
|
||||
this->p.PDOP = dop;
|
||||
this->p.ground_track = heading;
|
||||
this->p.sats_in_view = numSatellites;
|
||||
}
|
||||
// this->p.latitude_i = latitude;
|
||||
// this->p.longitude_i = longitude;
|
||||
// this->p.altitude = altitude;
|
||||
// this->p.PDOP = dop;
|
||||
// this->p.ground_track = heading;
|
||||
// this->p.sats_in_view = numSatellites;
|
||||
// }
|
||||
|
||||
// preferred method
|
||||
GPSStatus(bool hasLock, bool isConnected, const Position& pos)
|
||||
: Status()
|
||||
GPSStatus(bool hasLock, bool isConnected, const Position &pos) : Status()
|
||||
{
|
||||
this->hasLock = hasLock;
|
||||
this->isConnected = isConnected;
|
||||
@@ -61,9 +60,10 @@ class GPSStatus : public Status
|
||||
|
||||
bool getIsConnected() const { return isConnected; }
|
||||
|
||||
int32_t getLatitude() const {
|
||||
if (radioConfig.preferences.fixed_position){
|
||||
#if GPS_EXTRAVERBOSE
|
||||
int32_t getLatitude() const
|
||||
{
|
||||
if (config.position.fixed_position) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("WARNING: Using fixed latitude\n");
|
||||
#endif
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
@@ -73,9 +73,10 @@ class GPSStatus : public Status
|
||||
}
|
||||
}
|
||||
|
||||
int32_t getLongitude() const {
|
||||
if (radioConfig.preferences.fixed_position){
|
||||
#if GPS_EXTRAVERBOSE
|
||||
int32_t getLongitude() const
|
||||
{
|
||||
if (config.position.fixed_position) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("WARNING: Using fixed longitude\n");
|
||||
#endif
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
@@ -85,9 +86,10 @@ class GPSStatus : public Status
|
||||
}
|
||||
}
|
||||
|
||||
int32_t getAltitude() const {
|
||||
if (radioConfig.preferences.fixed_position){
|
||||
#if GPS_EXTRAVERBOSE
|
||||
int32_t getAltitude() const
|
||||
{
|
||||
if (config.position.fixed_position) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("WARNING: Using fixed altitude\n");
|
||||
#endif
|
||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||
@@ -105,18 +107,14 @@ class GPSStatus : public Status
|
||||
|
||||
bool matches(const GPSStatus *newStatus) const
|
||||
{
|
||||
#if GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n",
|
||||
newStatus->p.pos_timestamp, p.pos_timestamp);
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp);
|
||||
#endif
|
||||
return (newStatus->hasLock != hasLock ||
|
||||
newStatus->isConnected != isConnected ||
|
||||
newStatus->p.latitude_i != p.latitude_i ||
|
||||
newStatus->p.longitude_i != p.longitude_i ||
|
||||
newStatus->p.altitude != p.altitude ||
|
||||
newStatus->p.altitude_hae != p.altitude_hae ||
|
||||
newStatus->p.PDOP != p.PDOP ||
|
||||
newStatus->p.ground_track != p.ground_track ||
|
||||
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||
|
||||
newStatus->p.latitude_i != p.latitude_i || newStatus->p.longitude_i != p.longitude_i ||
|
||||
newStatus->p.altitude != p.altitude || newStatus->p.altitude_hae != p.altitude_hae ||
|
||||
newStatus->p.PDOP != p.PDOP || newStatus->p.ground_track != p.ground_track ||
|
||||
newStatus->p.ground_speed != p.ground_speed ||
|
||||
newStatus->p.sats_in_view != p.sats_in_view);
|
||||
}
|
||||
|
||||
@@ -125,8 +123,7 @@ class GPSStatus : public Status
|
||||
// Only update the status if values have actually changed
|
||||
bool isDirty = matches(newStatus);
|
||||
|
||||
if (isDirty && p.pos_timestamp &&
|
||||
(newStatus->p.pos_timestamp == p.pos_timestamp)) {
|
||||
if (isDirty && p.timestamp && (newStatus->p.timestamp == p.timestamp)) {
|
||||
// We can NEVER be in two locations at the same time! (also PR #886)
|
||||
DEBUG_MSG("BUG!! positional timestamp unchanged from prev solution\n");
|
||||
}
|
||||
@@ -140,11 +137,9 @@ class GPSStatus : public Status
|
||||
if (isDirty) {
|
||||
if (hasLock) {
|
||||
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
|
||||
DEBUG_MSG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, sats=%d\n",
|
||||
p.pos_timestamp,
|
||||
p.latitude_i * 1e-7, p.longitude_i * 1e-7,
|
||||
p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
||||
p.sats_in_view);
|
||||
DEBUG_MSG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp,
|
||||
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
||||
p.ground_speed * 1e-2, p.sats_in_view);
|
||||
} else
|
||||
DEBUG_MSG("No GPS lock\n");
|
||||
onNewStatus.notifyObservers(this);
|
||||
|
||||
@@ -15,7 +15,7 @@ bool scheduleOSCallback(PendableFunction callback, void *param1, uint32_t param2
|
||||
return xTimerPendFunctionCall(callback, param1, param2, pdMS_TO_TICKS(delayMsec));
|
||||
} */
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#ifdef ARCH_ESP32
|
||||
|
||||
// Super skanky quick hack to use hardware timers of the ESP32
|
||||
static hw_timer_t *timer;
|
||||
|
||||
@@ -11,13 +11,13 @@ template <class T> class Observable;
|
||||
*/
|
||||
template <class T> class Observer
|
||||
{
|
||||
Observable<T> *observed = NULL;
|
||||
std::list<Observable<T> *> observed;
|
||||
|
||||
public:
|
||||
virtual ~Observer();
|
||||
|
||||
/// Stop watching our current obserable
|
||||
void unobserve();
|
||||
/// Stop watching the obserable
|
||||
void unobserve(Observable<T> *o);
|
||||
|
||||
/// Start watching a specified observable
|
||||
void observe(Observable<T> *o);
|
||||
@@ -87,21 +87,21 @@ template <class T> class Observable
|
||||
|
||||
template <class T> Observer<T>::~Observer()
|
||||
{
|
||||
unobserve();
|
||||
for (typename std::list<Observable<T> *>::const_iterator iterator = observed.begin(); iterator != observed.end();
|
||||
++iterator) {
|
||||
(*iterator)->removeObserver(this);
|
||||
}
|
||||
observed.clear();
|
||||
}
|
||||
|
||||
template <class T> void Observer<T>::unobserve()
|
||||
template <class T> void Observer<T>::unobserve(Observable<T> *o)
|
||||
{
|
||||
if (observed)
|
||||
observed->removeObserver(this);
|
||||
observed = NULL;
|
||||
o->removeObserver(this);
|
||||
observed.remove(o);
|
||||
}
|
||||
|
||||
template <class T> void Observer<T>::observe(Observable<T> *o)
|
||||
{
|
||||
// We can only watch one thing at a time
|
||||
assert(!observed);
|
||||
|
||||
observed = o;
|
||||
observed.push_back(o);
|
||||
o->addObserver(this);
|
||||
}
|
||||
|
||||
547
src/Power.cpp
547
src/Power.cpp
@@ -1,39 +1,40 @@
|
||||
#include "configuration.h"
|
||||
#include "power.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "sleep.h"
|
||||
#include "utils.h"
|
||||
#include "buzz/buzz.h"
|
||||
|
||||
#ifdef TBEAM_V10
|
||||
// FIXME. nasty hack cleanup how we load axp192
|
||||
#undef AXP192_SLAVE_ADDRESS
|
||||
#include "axp20x.h"
|
||||
|
||||
AXP20X_Class axp;
|
||||
#ifdef HAS_PMU
|
||||
#include "XPowersLibInterface.hpp"
|
||||
#include "XPowersAXP2101.tpp"
|
||||
#include "XPowersAXP192.tpp"
|
||||
XPowersLibInterface *PMU = NULL;
|
||||
#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.
|
||||
class HasBatteryLevel {
|
||||
public:
|
||||
/**
|
||||
* Battery state of charge, from 0 to 100 or -1 for unknown
|
||||
*/
|
||||
virtual int getBattPercentage() { return -1; }
|
||||
class HasBatteryLevel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Battery state of charge, from 0 to 100 or -1 for unknown
|
||||
*/
|
||||
virtual int getBatteryPercent() { return -1; }
|
||||
|
||||
/**
|
||||
* The raw voltage of the battery or NAN if unknown
|
||||
*/
|
||||
virtual float getBattVoltage() { return NAN; }
|
||||
/**
|
||||
* The raw voltage of the battery or NAN if unknown
|
||||
*/
|
||||
virtual uint16_t getBattVoltage() { return 0; }
|
||||
|
||||
/**
|
||||
* return true if there is a battery installed in this unit
|
||||
*/
|
||||
virtual bool isBatteryConnect() { return false; }
|
||||
/**
|
||||
* return true if there is a battery installed in this unit
|
||||
*/
|
||||
virtual bool isBatteryConnect() { return false; }
|
||||
|
||||
virtual bool isVBUSPlug() { return false; }
|
||||
virtual bool isChargeing() { return false; }
|
||||
virtual bool isVbusIn() { return false; }
|
||||
virtual bool isCharging() { return false; }
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -44,7 +45,7 @@ Power *power;
|
||||
using namespace meshtastic;
|
||||
|
||||
#ifndef AREF_VOLTAGE
|
||||
#if defined(NRF52_SERIES)
|
||||
#if defined(ARCH_NRF52)
|
||||
/*
|
||||
* Internal Reference is +/-0.6V, with an adjustable gain of 1/6, 1/5, 1/4,
|
||||
* 1/3, 1/2 or 1, meaning 3.6, 3.0, 2.4, 1.8, 1.2 or 0.6V for the ADC levels.
|
||||
@@ -75,14 +76,14 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
*
|
||||
* FIXME - use a lipo lookup table, the current % full is super wrong
|
||||
*/
|
||||
virtual int getBattPercentage() override
|
||||
virtual int getBatteryPercent() override
|
||||
{
|
||||
float v = getBattVoltage();
|
||||
|
||||
if (v < noBatVolt)
|
||||
return -1; // If voltage is super low assume no battery installed
|
||||
|
||||
#ifndef NRF52_SERIES
|
||||
#ifdef ARCH_ESP32
|
||||
// This does not work on a RAK4631 with battery connected
|
||||
if (v > chargingVolt)
|
||||
return 0; // While charging we can't report % full on the battery
|
||||
@@ -94,29 +95,40 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
/**
|
||||
* The raw voltage of the batteryin millivolts or NAN if unknown
|
||||
*/
|
||||
virtual float getBattVoltage() override
|
||||
virtual uint16_t getBattVoltage() override
|
||||
{
|
||||
|
||||
#ifndef ADC_MULTIPLIER
|
||||
#define ADC_MULTIPLIER 2.0
|
||||
#endif
|
||||
// Override variant or default ADC_MULTIPLIER if we have the override pref
|
||||
float operativeAdcMultiplier = radioConfig.preferences.adc_multiplier_override > 0 ?
|
||||
radioConfig.preferences.adc_multiplier_override :
|
||||
ADC_MULTIPLIER;
|
||||
#endif
|
||||
|
||||
#ifdef BATTERY_PIN
|
||||
// Do not call analogRead() often.
|
||||
// Override variant or default ADC_MULTIPLIER if we have the override pref
|
||||
float operativeAdcMultiplier = config.power.adc_multiplier_override > 0
|
||||
? config.power.adc_multiplier_override
|
||||
: ADC_MULTIPLIER;
|
||||
// Do not call analogRead() often.
|
||||
const uint32_t min_read_interval = 5000;
|
||||
if (millis() - last_read_time_ms > min_read_interval) {
|
||||
last_read_time_ms = millis();
|
||||
|
||||
#ifdef BATTERY_SENSE_SAMPLES
|
||||
//Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic environment.
|
||||
uint32_t raw = 0;
|
||||
for(uint32_t i=0; i<BATTERY_SENSE_SAMPLES;i++){
|
||||
raw += analogRead(BATTERY_PIN);
|
||||
}
|
||||
raw = raw/BATTERY_SENSE_SAMPLES;
|
||||
#else
|
||||
uint32_t raw = analogRead(BATTERY_PIN);
|
||||
#endif
|
||||
|
||||
float scaled;
|
||||
#ifndef VBAT_RAW_TO_SCALED
|
||||
#ifndef VBAT_RAW_TO_SCALED
|
||||
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
|
||||
#else
|
||||
scaled = VBAT_RAW_TO_SCALED(raw); //defined in variant.h
|
||||
#endif
|
||||
#else
|
||||
scaled = VBAT_RAW_TO_SCALED(raw); // defined in variant.h
|
||||
#endif
|
||||
// DEBUG_MSG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
|
||||
last_read_value = scaled;
|
||||
return scaled;
|
||||
@@ -124,36 +136,50 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
return last_read_value;
|
||||
}
|
||||
#else
|
||||
return NAN;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if there is a battery installed in this unit
|
||||
*/
|
||||
virtual bool isBatteryConnect() override { return getBattPercentage() != -1; }
|
||||
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
|
||||
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
/// in power
|
||||
virtual bool isVBUSPlug() override { return getBattVoltage() > chargingVolt; }
|
||||
virtual bool isVbusIn() override { return getBattVoltage() > chargingVolt; }
|
||||
|
||||
/// Assume charging if we have a battery and external power is connected.
|
||||
/// we can't be smart enough to say 'full'?
|
||||
virtual bool isChargeing() override { return isBatteryConnect() && isVBUSPlug(); }
|
||||
virtual bool isCharging() override { return isBatteryConnect() && isVbusIn(); }
|
||||
|
||||
private:
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
/// in power
|
||||
|
||||
#ifndef BAT_FULLVOLT
|
||||
#define BAT_FULLVOLT 4200
|
||||
#endif
|
||||
#ifndef BAT_EMPTYVOLT
|
||||
#define BAT_EMPTYVOLT 3270
|
||||
#endif
|
||||
#ifndef BAT_CHARGINGVOLT
|
||||
#define BAT_CHARGINGVOLT 4210
|
||||
#endif
|
||||
#ifndef BAT_NOBATVOLT
|
||||
#define BAT_NOBATVOLT 2230
|
||||
#endif
|
||||
|
||||
/// For heltecs with no battery connected, the measured voltage is 2204, so raising to 2230 from 2100
|
||||
const float fullVolt = 4200, emptyVolt = 3270, chargingVolt = 4210, noBatVolt = 2230;
|
||||
const float fullVolt = BAT_FULLVOLT, emptyVolt = BAT_EMPTYVOLT, chargingVolt = BAT_CHARGINGVOLT, noBatVolt = BAT_NOBATVOLT;
|
||||
float last_read_value = 0.0;
|
||||
uint32_t last_read_time_ms = 0;
|
||||
};
|
||||
|
||||
AnalogBatteryLevel analogLevel;
|
||||
|
||||
Power::Power() : OSThread("Power") {
|
||||
Power::Power() : OSThread("Power")
|
||||
{
|
||||
statusHandler = {};
|
||||
low_voltage_counter = 0;
|
||||
}
|
||||
@@ -166,13 +192,13 @@ bool Power::analogInit()
|
||||
// disable any internal pullups
|
||||
pinMode(BATTERY_PIN, INPUT);
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#ifdef ARCH_ESP32
|
||||
// ESP32 needs special analog stuff
|
||||
adcAttachPin(BATTERY_PIN);
|
||||
#endif
|
||||
#ifdef NRF52_SERIES
|
||||
#ifdef ARCH_NRF52
|
||||
#ifdef VBAT_AR_INTERNAL
|
||||
analogReference(VBAT_AR_INTERNAL);
|
||||
analogReference(VBAT_AR_INTERNAL);
|
||||
#else
|
||||
analogReference(AR_INTERNAL); // 3.6V
|
||||
#endif
|
||||
@@ -181,9 +207,10 @@ bool Power::analogInit()
|
||||
#ifndef BATTERY_SENSE_RESOLUTION_BITS
|
||||
#define BATTERY_SENSE_RESOLUTION_BITS 10
|
||||
#endif
|
||||
|
||||
|
||||
// adcStart(BATTERY_PIN);
|
||||
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
|
||||
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11
|
||||
// depending on needed resolution.
|
||||
batteryLevel = &analogLevel;
|
||||
return true;
|
||||
#else
|
||||
@@ -193,7 +220,7 @@ bool Power::analogInit()
|
||||
|
||||
bool Power::setup()
|
||||
{
|
||||
bool found = axp192Init();
|
||||
bool found = axpChipInit();
|
||||
|
||||
if (!found) {
|
||||
found = analogInit();
|
||||
@@ -206,10 +233,21 @@ bool Power::setup()
|
||||
|
||||
void Power::shutdown()
|
||||
{
|
||||
#ifdef TBEAM_V10
|
||||
screen->setOn(false);
|
||||
#if defined(USE_EINK) && defined(PIN_EINK_EN)
|
||||
digitalWrite(PIN_EINK_EN, LOW); //power off backlight first
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PMU
|
||||
DEBUG_MSG("Shutting down\n");
|
||||
axp.shutdown();
|
||||
#elif NRF52_SERIES
|
||||
if(PMU) {
|
||||
PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
|
||||
PMU->shutdown();
|
||||
}
|
||||
#elif defined(ARCH_NRF52)
|
||||
playBeep();
|
||||
ledOff(PIN_LED1);
|
||||
ledOff(PIN_LED2);
|
||||
doDeepSleep(DELAY_FOREVER);
|
||||
#endif
|
||||
}
|
||||
@@ -226,8 +264,8 @@ void Power::readPowerStatus()
|
||||
if (hasBattery) {
|
||||
batteryVoltageMv = batteryLevel->getBattVoltage();
|
||||
// If the AXP192 returns a valid battery percentage, use it
|
||||
if (batteryLevel->getBattPercentage() >= 0) {
|
||||
batteryChargePercent = batteryLevel->getBattPercentage();
|
||||
if (batteryLevel->getBatteryPercent() >= 0) {
|
||||
batteryChargePercent = batteryLevel->getBatteryPercent();
|
||||
} else {
|
||||
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
|
||||
// In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in
|
||||
@@ -240,30 +278,29 @@ void Power::readPowerStatus()
|
||||
|
||||
// Notify any status instances that are observing us
|
||||
const PowerStatus powerStatus2 =
|
||||
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse,
|
||||
batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
|
||||
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVbusIn() ? OptTrue : OptFalse,
|
||||
batteryLevel->isCharging() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
|
||||
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
|
||||
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
|
||||
newStatus.notifyObservers(&powerStatus2);
|
||||
|
||||
|
||||
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
|
||||
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
|
||||
#ifdef NRF52_SERIES
|
||||
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()){
|
||||
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS){
|
||||
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
|
||||
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
|
||||
#ifdef ARCH_NRF52
|
||||
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
|
||||
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) {
|
||||
low_voltage_counter++;
|
||||
if (low_voltage_counter>3)
|
||||
if (low_voltage_counter > 3)
|
||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||
} else {
|
||||
low_voltage_counter = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#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
|
||||
#endif
|
||||
} else {
|
||||
// No power sensing on this board - tell everyone else we have no idea what is happening
|
||||
const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
|
||||
@@ -275,41 +312,47 @@ int32_t Power::runOnce()
|
||||
{
|
||||
readPowerStatus();
|
||||
|
||||
#ifdef TBEAM_V10
|
||||
#ifdef HAS_PMU
|
||||
// WE no longer use the IRQ line to wake the CPU (due to false wakes from sleep), but we do poll
|
||||
// the IRQ status by reading the registers over I2C
|
||||
axp.readIRQ();
|
||||
if(PMU) {
|
||||
|
||||
if (axp.isVbusRemoveIRQ()) {
|
||||
DEBUG_MSG("USB unplugged\n");
|
||||
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||
}
|
||||
if (axp.isVbusPlugInIRQ()) {
|
||||
DEBUG_MSG("USB plugged In\n");
|
||||
powerFSM.trigger(EVENT_POWER_CONNECTED);
|
||||
}
|
||||
/*
|
||||
Other things we could check if we cared...
|
||||
PMU->getIrqStatus();
|
||||
|
||||
if (axp.isChargingIRQ()) {
|
||||
DEBUG_MSG("Battery start charging\n");
|
||||
if(PMU->isVbusRemoveIrq()){
|
||||
DEBUG_MSG("USB unplugged\n");
|
||||
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||
}
|
||||
|
||||
if (PMU->isVbusInsertIrq()) {
|
||||
DEBUG_MSG("USB plugged In\n");
|
||||
powerFSM.trigger(EVENT_POWER_CONNECTED);
|
||||
}
|
||||
|
||||
/*
|
||||
Other things we could check if we cared...
|
||||
|
||||
if (PMU->isBatChagerStartIrq()) {
|
||||
DEBUG_MSG("Battery start charging\n");
|
||||
}
|
||||
if (PMU->isBatChagerDoneIrq()) {
|
||||
DEBUG_MSG("Battery fully charged\n");
|
||||
}
|
||||
if (PMU->isBatInsertIrq()) {
|
||||
DEBUG_MSG("Battery inserted\n");
|
||||
}
|
||||
if (PMU->isBatRemoveIrq()) {
|
||||
DEBUG_MSG("Battery removed\n");
|
||||
}
|
||||
*/
|
||||
if (PMU->isPekeyLongPressIrq()) {
|
||||
DEBUG_MSG("PEK long button press\n");
|
||||
screen->setOn(false);
|
||||
}
|
||||
|
||||
PMU->clearIrqStatus();
|
||||
}
|
||||
if (axp.isChargingDoneIRQ()) {
|
||||
DEBUG_MSG("Battery fully charged\n");
|
||||
}
|
||||
if (axp.isBattPlugInIRQ()) {
|
||||
DEBUG_MSG("Battery inserted\n");
|
||||
}
|
||||
if (axp.isBattRemoveIRQ()) {
|
||||
DEBUG_MSG("Battery removed\n");
|
||||
}
|
||||
if (axp.isPEKShortPressIRQ()) {
|
||||
DEBUG_MSG("PEK short button press\n");
|
||||
}
|
||||
*/
|
||||
axp.clearIRQ();
|
||||
#endif
|
||||
|
||||
// Only read once every 20 seconds once the power status for the app has been initialized
|
||||
return (statusHandler && statusHandler->isInitialized()) ? (1000 * 20) : RUN_SAME;
|
||||
}
|
||||
@@ -322,110 +365,238 @@ int32_t Power::runOnce()
|
||||
share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this on!) LDO1
|
||||
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
|
||||
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
|
||||
*
|
||||
*/
|
||||
bool Power::axp192Init()
|
||||
bool Power::axpChipInit()
|
||||
{
|
||||
#ifdef TBEAM_V10
|
||||
if (axp192_found) {
|
||||
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
|
||||
batteryLevel = &axp;
|
||||
|
||||
DEBUG_MSG("AXP192 Begin PASS\n");
|
||||
#ifdef HAS_PMU
|
||||
|
||||
// axp.setChgLEDMode(LED_BLINK_4HZ);
|
||||
DEBUG_MSG("DCDC1: %s\n", axp.isDCDC1Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("DCDC2: %s\n", axp.isDCDC2Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("LDO2: %s\n", axp.isLDO2Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("LDO3: %s\n", axp.isLDO3Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("----------------------------------------\n");
|
||||
TwoWire * w = NULL;
|
||||
|
||||
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA radio
|
||||
// axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS main power - now turned on in setGpsPower
|
||||
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
|
||||
axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
|
||||
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
|
||||
axp.setDCDC1Voltage(3300); // for the OLED power
|
||||
|
||||
DEBUG_MSG("DCDC1: %s\n", axp.isDCDC1Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("DCDC2: %s\n", axp.isDCDC2Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("LDO2: %s\n", axp.isLDO2Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("LDO3: %s\n", axp.isLDO3Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
|
||||
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
|
||||
|
||||
if (radioConfig.preferences.charge_current == ChargeCurrent_MAUnset) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA100) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_100MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA190) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_190MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA280) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_280MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA360) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_360MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA450) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA550) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_550MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA630) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_630MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA700) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_700MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA780) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_780MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA880) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_880MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA960) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_960MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1000) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1000MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1080) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1080MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1160) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1160MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1240) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1240MA);
|
||||
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1320) {
|
||||
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
// Not connected
|
||||
//val = 0xfc;
|
||||
//axp._writeByte(AXP202_VHTF_CHGSET, 1, &val); // Set temperature protection
|
||||
|
||||
//not used
|
||||
//val = 0x46;
|
||||
//axp._writeByte(AXP202_OFF_CTL, 1, &val); // enable bat detection
|
||||
// Use macro to distinguish which wire is used by PMU
|
||||
#ifdef PMU_USE_WIRE1
|
||||
w = &Wire1;
|
||||
#else
|
||||
w = &Wire;
|
||||
#endif
|
||||
axp.debugCharging();
|
||||
|
||||
#ifdef PMU_IRQ
|
||||
pinMode(PMU_IRQ, INPUT);
|
||||
attachInterrupt(
|
||||
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
|
||||
|
||||
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1);
|
||||
// we do not look for AXP202_CHARGING_FINISHED_IRQ & AXP202_CHARGING_IRQ because it occurs repeatedly while there is
|
||||
// no battery also it could cause inadvertent waking from light sleep just because the battery filled
|
||||
// we don't look for AXP202_BATT_REMOVED_IRQ because it occurs repeatedly while no battery installed
|
||||
// we don't look at AXP202_VBUS_REMOVED_IRQ because we don't have anything hooked to vbus
|
||||
axp.enableIRQ(AXP202_BATT_CONNECT_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_PEK_SHORTPRESS_IRQ, 1);
|
||||
|
||||
axp.clearIRQ();
|
||||
#endif
|
||||
readPowerStatus();
|
||||
/**
|
||||
* It is not necessary to specify the wire pin,
|
||||
* just input the wire, because the wire has been initialized in main.cpp
|
||||
*/
|
||||
if (!PMU) {
|
||||
PMU = new XPowersAXP2101(*w);
|
||||
if (!PMU->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find AXP2101 power management\n");
|
||||
delete PMU;
|
||||
PMU = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("AXP192 Begin FAIL\n");
|
||||
DEBUG_MSG("AXP2101 PMU init succeeded, using AXP2101 PMU\n");
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("AXP192 not found\n");
|
||||
}
|
||||
|
||||
return axp192_found;
|
||||
if (!PMU) {
|
||||
PMU = new XPowersAXP192(*w);
|
||||
if (!PMU->init()) {
|
||||
DEBUG_MSG("Warning: Failed to find AXP192 power management\n");
|
||||
delete PMU;
|
||||
PMU = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("AXP192 PMU init succeeded, using AXP192 PMU\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!PMU) {
|
||||
/*
|
||||
* In XPowersLib, if the XPowersAXPxxx object is released, Wire.end() will be called at the same time.
|
||||
* In order not to affect other devices, if the initialization of the PMU fails, Wire needs to be re-initialized once,
|
||||
* if there are multiple devices sharing the bus.
|
||||
* * */
|
||||
#ifndef PMU_USE_WIRE1
|
||||
w->begin(I2C_SDA, I2C_SCL);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
batteryLevel = PMU;
|
||||
|
||||
if (PMU->getChipModel() == XPOWERS_AXP192) {
|
||||
|
||||
// lora radio power channel
|
||||
PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_LDO2);
|
||||
|
||||
|
||||
// oled module power channel,
|
||||
// disable it will cause abnormal communication between boot and AXP power supply,
|
||||
// do not turn it off
|
||||
PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
|
||||
// enable oled power
|
||||
PMU->enablePowerOutput(XPOWERS_DCDC1);
|
||||
|
||||
|
||||
// gnss module power channel - now turned on in setGpsPower
|
||||
PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
|
||||
// PMU->enablePowerOutput(XPOWERS_LDO3);
|
||||
|
||||
|
||||
//protected oled power source
|
||||
PMU->setProtectedChannel(XPOWERS_DCDC1);
|
||||
//protected esp32 power source
|
||||
PMU->setProtectedChannel(XPOWERS_DCDC3);
|
||||
|
||||
//disable not use channel
|
||||
PMU->disablePowerOutput(XPOWERS_DCDC2);
|
||||
|
||||
//disable all axp chip interrupt
|
||||
PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
|
||||
|
||||
// Set constant current charging current
|
||||
PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_450MA);
|
||||
|
||||
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
||||
|
||||
// t-beam s3 core
|
||||
|
||||
/**
|
||||
* gnss module power channel
|
||||
* The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during initialization
|
||||
*/
|
||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO4);
|
||||
|
||||
// lora radio power channel
|
||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO3);
|
||||
|
||||
// m.2 interface
|
||||
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_DCDC3);
|
||||
|
||||
/**
|
||||
* ALDO2 cannot be turned off.
|
||||
* It is a necessary condition for sensor communication.
|
||||
* It must be turned on to properly access the sensor and screen
|
||||
* It is also responsible for the power supply of PCF8563
|
||||
*/
|
||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||
|
||||
// 6-axis , magnetometer ,bme280 , oled screen power channel
|
||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO1);
|
||||
|
||||
// sdcard power channle
|
||||
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_BLDO1);
|
||||
|
||||
// PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
|
||||
// PMU->enablePowerOutput(XPOWERS_DCDC4);
|
||||
|
||||
//not use channel
|
||||
PMU->disablePowerOutput(XPOWERS_DCDC2); //not elicited
|
||||
PMU->disablePowerOutput(XPOWERS_DCDC5); //not elicited
|
||||
PMU->disablePowerOutput(XPOWERS_DLDO1); //Invalid power channel, it does not exist
|
||||
PMU->disablePowerOutput(XPOWERS_DLDO2); //Invalid power channel, it does not exist
|
||||
PMU->disablePowerOutput(XPOWERS_VBACKUP);
|
||||
|
||||
//disable all axp chip interrupt
|
||||
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
|
||||
|
||||
//Set the constant current charging current of AXP2101, temporarily use 500mA by default
|
||||
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
|
||||
|
||||
}
|
||||
|
||||
|
||||
PMU->clearIrqStatus();
|
||||
|
||||
// TBeam1.1 /T-Beam S3-Core has no external TS detection,
|
||||
// it needs to be disabled, otherwise it will cause abnormal charging
|
||||
PMU->disableTSPinMeasure();
|
||||
|
||||
// PMU->enableSystemVoltageMeasure();
|
||||
PMU->enableVbusVoltageMeasure();
|
||||
PMU->enableBattVoltageMeasure();
|
||||
|
||||
DEBUG_MSG("=======================================================================\n");
|
||||
if (PMU->isChannelAvailable(XPOWERS_DCDC1)) {
|
||||
DEBUG_MSG("DC1 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_DCDC2)) {
|
||||
DEBUG_MSG("DC2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_DCDC3)) {
|
||||
DEBUG_MSG("DC3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_DCDC4)) {
|
||||
DEBUG_MSG("DC4 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_LDO2)) {
|
||||
DEBUG_MSG("LDO2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO2));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_LDO3)) {
|
||||
DEBUG_MSG("LDO3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO3));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_ALDO1)) {
|
||||
DEBUG_MSG("ALDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_ALDO2)) {
|
||||
DEBUG_MSG("ALDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_ALDO3)) {
|
||||
DEBUG_MSG("ALDO3: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_ALDO4)) {
|
||||
DEBUG_MSG("ALDO4: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_BLDO1)) {
|
||||
DEBUG_MSG("BLDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
|
||||
}
|
||||
if (PMU->isChannelAvailable(XPOWERS_BLDO2)) {
|
||||
DEBUG_MSG("BLDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
|
||||
}
|
||||
DEBUG_MSG("=======================================================================\n");
|
||||
|
||||
|
||||
//Set up the charging voltage, AXP2101/AXP192 4.2V gear is the same
|
||||
// XPOWERS_AXP192_CHG_VOL_4V2 = XPOWERS_AXP2101_CHG_VOL_4V2
|
||||
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
||||
|
||||
// Set PMU shutdown voltage at 2.6V to maximize battery utilization
|
||||
PMU->setSysPowerDownVoltage(2600);
|
||||
|
||||
|
||||
|
||||
#ifdef PMU_IRQ
|
||||
uint64_t pmuIrqMask = 0;
|
||||
|
||||
if (PMU->getChipModel() == XPOWERS_AXP192) {
|
||||
pmuIrqMask = XPOWERS_AXP192_VBUS_INSERT_IRQ | XPOWERS_AXP192_BAT_INSERT_IRQ | XPOWERS_AXP192_PKEY_SHORT_IRQ;
|
||||
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
||||
pmuIrqMask = XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_PKEY_SHORT_IRQ;
|
||||
}
|
||||
|
||||
pinMode(PMU_IRQ, INPUT);
|
||||
attachInterrupt(
|
||||
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
|
||||
|
||||
// we do not look for AXPXXX_CHARGING_FINISHED_IRQ & AXPXXX_CHARGING_IRQ because it occurs repeatedly while there is
|
||||
// no battery also it could cause inadvertent waking from light sleep just because the battery filled
|
||||
// we don't look for AXPXXX_BATT_REMOVED_IRQ because it occurs repeatedly while no battery installed
|
||||
// we don't look at AXPXXX_VBUS_REMOVED_IRQ because we don't have anything hooked to vbus
|
||||
PMU->enableIRQ(pmuIrqMask);
|
||||
|
||||
PMU->clearIrqStatus();
|
||||
#endif /*PMU_IRQ*/
|
||||
|
||||
readPowerStatus();
|
||||
|
||||
pmu_found = true;
|
||||
|
||||
return pmu_found;
|
||||
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
@@ -11,30 +11,30 @@
|
||||
/// Should we behave as if we have AC power now?
|
||||
static bool isPowered()
|
||||
{
|
||||
// Completely circumvents the battery / power sensing logic and assumes constant power source
|
||||
if (radioConfig.preferences.is_always_powered) {
|
||||
// Circumvent the battery sensing logic and assumes constant power if no battery pin or power mgmt IC
|
||||
#if !defined(BATTERY_PIN) && !defined(HAS_AXP192) && !defined(HAS_AXP2101)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool isRouter = (radioConfig.preferences.role == Role_Router ? 1 : 0);
|
||||
bool isRouter = (config.device.role == Config_DeviceConfig_Role_ROUTER ? 1 : 0);
|
||||
|
||||
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
|
||||
// We assume routers might be powered all the time, but from a low current (solar) source
|
||||
bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
|
||||
bool isPowerSavingMode = config.power.is_power_saving || isRouter;
|
||||
|
||||
/* To determine if we're externally powered, assumptions
|
||||
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.
|
||||
*/
|
||||
return !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
||||
return !isPowerSavingMode && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
|
||||
}
|
||||
|
||||
static void sdsEnter()
|
||||
{
|
||||
DEBUG_MSG("Enter state: SDS\n");
|
||||
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
||||
doDeepSleep(getPref_sds_secs() * 1000LL);
|
||||
doDeepSleep(config.power.sds_secs * 1000);
|
||||
}
|
||||
|
||||
extern Power *power;
|
||||
@@ -51,7 +51,7 @@ static uint32_t secsSlept;
|
||||
|
||||
static void lsEnter()
|
||||
{
|
||||
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", getPref_ls_secs());
|
||||
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", config.power.ls_secs);
|
||||
screen->setOn(false);
|
||||
secsSlept = 0; // How long have we been sleeping this time
|
||||
|
||||
@@ -62,10 +62,10 @@ static void lsIdle()
|
||||
{
|
||||
// DEBUG_MSG("lsIdle begin ls_secs=%u\n", getPref_ls_secs());
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#ifdef ARCH_ESP32
|
||||
|
||||
// Do we have more sleeping to do?
|
||||
if (secsSlept < getPref_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;
|
||||
|
||||
@@ -78,7 +78,7 @@ static void lsIdle()
|
||||
case ESP_SLEEP_WAKEUP_TIMER:
|
||||
// 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
|
||||
|
||||
secsSlept += sleepTime;
|
||||
@@ -199,8 +199,7 @@ static void onEnter()
|
||||
|
||||
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 ((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;
|
||||
@@ -238,10 +237,10 @@ Fsm powerFSM(&stateBOOT);
|
||||
|
||||
void PowerFSM_setup()
|
||||
{
|
||||
bool isRouter = (radioConfig.preferences.role == Role_Router ? 1 : 0);
|
||||
bool isRouter = (config.device.role == Config_DeviceConfig_Role_ROUTER ? 1 : 0);
|
||||
bool hasPower = isPowered();
|
||||
|
||||
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
|
||||
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0);
|
||||
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
|
||||
|
||||
// wake timer expired or a packet arrived
|
||||
@@ -250,8 +249,7 @@ void PowerFSM_setup()
|
||||
|
||||
// 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
|
||||
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL,
|
||||
"Received packet, exiting light sleep");
|
||||
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, exiting light sleep");
|
||||
powerFSM.add_transition(&stateNB, &stateNB, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, resetting win wake");
|
||||
|
||||
// Handle press events - note: we ignore button presses when in API mode
|
||||
@@ -260,8 +258,7 @@ void PowerFSM_setup()
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press");
|
||||
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
|
||||
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress,
|
||||
"Press"); // Allow button to work while in serial API
|
||||
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress, "Press"); // Allow button to work while in serial API
|
||||
|
||||
// Handle critically low power battery by forcing deep sleep
|
||||
powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
|
||||
@@ -332,40 +329,26 @@ void PowerFSM_setup()
|
||||
powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
|
||||
powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
|
||||
|
||||
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
|
||||
powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout");
|
||||
|
||||
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
|
||||
State *lowPowerState = &stateLS;
|
||||
|
||||
uint32_t meshSds = 0;
|
||||
|
||||
#ifndef NRF52_SERIES
|
||||
#ifdef ARCH_ESP32
|
||||
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
||||
|
||||
// See: https://github.com/meshtastic/Meshtastic-device/issues/1071
|
||||
if (isRouter || radioConfig.preferences.is_power_saving) {
|
||||
// See: https://github.com/meshtastic/firmware/issues/1071
|
||||
if (isRouter || config.power.is_power_saving) {
|
||||
powerFSM.add_timed_transition(&stateNB, &stateLS, getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout");
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateLS, getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL, "Bluetooth timeout");
|
||||
}
|
||||
|
||||
// I don't think this transition is correct, turning off for now - @geeksville
|
||||
// powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
|
||||
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
|
||||
meshSds = getPref_mesh_sds_timeout_secs();
|
||||
|
||||
} else {
|
||||
|
||||
meshSds = UINT32_MAX;
|
||||
}
|
||||
|
||||
#else
|
||||
#elif defined (ARCH_NRF52)
|
||||
lowPowerState = &stateDARK;
|
||||
meshSds = UINT32_MAX; // Workaround for now: Don't go into deep sleep on the RAK4631
|
||||
#endif
|
||||
|
||||
if (meshSds != UINT32_MAX)
|
||||
powerFSM.add_timed_transition(lowPowerState, &stateSDS, meshSds * 1000, NULL, "mesh timeout");
|
||||
// removing for now, because some users don't even have phones
|
||||
// powerFSM.add_timed_transition(lowPowerState, &stateSDS, getPref_phone_sds_timeout_sec() * 1000, NULL, "phone
|
||||
// timeout");
|
||||
if (config.power.sds_secs != UINT32_MAX)
|
||||
powerFSM.add_timed_transition(lowPowerState, &stateSDS, config.power.sds_secs * 1000, NULL, "mesh timeout");
|
||||
|
||||
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "configuration.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "main.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "power.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "power.h"
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
@@ -26,13 +26,16 @@ class PowerFSMThread : public OSThread
|
||||
|
||||
if (powerStatus->getHasUSB()) {
|
||||
timeLastPowered = millis();
|
||||
} else if (radioConfig.preferences.on_battery_shutdown_after_secs > 0 &&
|
||||
millis() > timeLastPowered + (1000 * radioConfig.preferences.on_battery_shutdown_after_secs)) { //shutdown after 30 minutes unpowered
|
||||
} else if (config.power.on_battery_shutdown_after_secs > 0 &&
|
||||
millis() >
|
||||
timeLastPowered +
|
||||
(1000 *
|
||||
config.power.on_battery_shutdown_after_secs)) { // shutdown after 30 minutes unpowered
|
||||
powerFSM.trigger(EVENT_SHUTDOWN);
|
||||
}
|
||||
|
||||
|
||||
return 10;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace concurrency
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "configuration.h"
|
||||
#include "RedirectablePrint.h"
|
||||
#include "RTC.h"
|
||||
#include "NodeDB.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
// #include "wifi/WiFiServerAPI.h"
|
||||
#include <assert.h>
|
||||
@@ -30,7 +31,9 @@ size_t RedirectablePrint::write(uint8_t c)
|
||||
// optionally send chars to TCP also
|
||||
//WiFiServerPort::debugOut(c);
|
||||
|
||||
dest->write(c);
|
||||
if (!config.has_lora || config.device.serial_enabled)
|
||||
dest->write(c);
|
||||
|
||||
return 1; // We always claim one was written, rather than trusting what the
|
||||
// serial port said (which could be zero)
|
||||
}
|
||||
@@ -38,19 +41,17 @@ size_t RedirectablePrint::write(uint8_t c)
|
||||
size_t RedirectablePrint::vprintf(const char *format, va_list arg)
|
||||
{
|
||||
va_list copy;
|
||||
static char printBuf[160];
|
||||
|
||||
va_copy(copy, arg);
|
||||
int len = vsnprintf(printBuf, printBufLen, format, copy);
|
||||
size_t len = vsnprintf(printBuf, sizeof(printBuf), format, copy);
|
||||
va_end(copy);
|
||||
if (len < 0) {
|
||||
va_end(arg);
|
||||
return 0;
|
||||
};
|
||||
if (len >= (int)printBufLen) {
|
||||
delete[] printBuf;
|
||||
printBufLen *= 2;
|
||||
printBuf = new char[printBufLen];
|
||||
len = vsnprintf(printBuf, printBufLen, format, arg);
|
||||
|
||||
// If the resulting string is longer than sizeof(printBuf)-1 characters, the remaining characters are still counted for the return value
|
||||
|
||||
if (len > sizeof(printBuf) - 1) {
|
||||
len = sizeof(printBuf) - 1;
|
||||
printBuf[sizeof(printBuf) - 2] = '\n';
|
||||
}
|
||||
|
||||
len = Print::write(printBuf, len);
|
||||
@@ -72,7 +73,7 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
|
||||
|
||||
// If we are the first message on a report, include the header
|
||||
if (!isContinuationMessage) {
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet);
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
|
||||
if (rtc_sec > 0) {
|
||||
long hms = rtc_sec % SEC_PER_DAY;
|
||||
// hms += tz.tz_dsttime * SEC_PER_HOUR;
|
||||
@@ -107,4 +108,4 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,6 @@ class RedirectablePrint : public Print
|
||||
{
|
||||
Print *dest;
|
||||
|
||||
/// We dynamically grow this scratch buffer if necessary
|
||||
char *printBuf = new char[64];
|
||||
size_t printBufLen = 64;
|
||||
|
||||
/// Used to allow multiple logDebug messages to appear on a single log line
|
||||
bool isContinuationMessage = false;
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "configuration.h"
|
||||
#include "SerialConsole.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#define Port Serial
|
||||
// Defaulting to the formerly removed phone_timeout_secs value of 15 minutes
|
||||
#define SERIAL_CONNECTION_TIMEOUT (15 * 60) * 1000UL
|
||||
|
||||
SerialConsole *console;
|
||||
|
||||
@@ -18,6 +20,9 @@ void consolePrintf(const char *format, ...)
|
||||
va_start(arg, format);
|
||||
console->vprintf(format, arg);
|
||||
va_end(arg);
|
||||
#ifdef ARCH_ESP32
|
||||
console->flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
@@ -28,7 +33,7 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
|
||||
|
||||
Port.begin(SERIAL_BAUD);
|
||||
#ifdef NRF52_SERIES
|
||||
#ifdef ARCH_NRF52
|
||||
time_t timeout = millis();
|
||||
while (!Port) {
|
||||
if ((millis() - timeout) < 5000) {
|
||||
@@ -41,11 +46,12 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
emitRebooted();
|
||||
}
|
||||
|
||||
|
||||
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
bool SerialConsole::checkIsConnected()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
return (now - lastContactMsec) < getPref_phone_timeout_secs() * 1000UL;
|
||||
return (now - lastContactMsec) < SERIAL_CONNECTION_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,11 +60,15 @@ bool SerialConsole::checkIsConnected()
|
||||
*/
|
||||
bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
||||
{
|
||||
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
||||
if (!radioConfig.preferences.debug_log_enabled)
|
||||
setDestination(&noopPrint);
|
||||
canWrite = true;
|
||||
|
||||
return StreamAPI::handleToRadio(buf, len);
|
||||
}
|
||||
// only talk to the API once the configuration has been loaded and we're sure the serial port is not disabled.
|
||||
if (config.has_lora && config.device.serial_enabled) {
|
||||
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
||||
if (!config.device.debug_log_enabled)
|
||||
setDestination(&noopPrint);
|
||||
canWrite = true;
|
||||
|
||||
return StreamAPI::handleToRadio(buf, len);
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "buzz.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef NRF52_SERIES
|
||||
#include "variant.h"
|
||||
#endif
|
||||
#include "NodeDB.h"
|
||||
|
||||
#ifndef PIN_BUZZER
|
||||
|
||||
@@ -12,8 +9,13 @@ void playBeep(){};
|
||||
void playStartMelody(){};
|
||||
void playShutdownMelody(){};
|
||||
|
||||
#else
|
||||
#ifdef M5STACK
|
||||
#include "Speaker.h"
|
||||
TONE Tone;
|
||||
#else
|
||||
#include "Tone.h"
|
||||
#endif
|
||||
|
||||
extern "C" void delay(uint32_t dwMs);
|
||||
|
||||
@@ -35,32 +37,49 @@ struct ToneDuration {
|
||||
#define NOTE_A3 220
|
||||
#define NOTE_AS3 233
|
||||
#define NOTE_B3 247
|
||||
#define NOTE_CS4 277
|
||||
|
||||
const int DURATION_1_8 = 125; // 1/8 note
|
||||
const int DURATION_1_4 = 250; // 1/4 note
|
||||
|
||||
void playTones(const ToneDuration *tone_durations, int size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
const auto &tone_duration = tone_durations[i];
|
||||
tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms);
|
||||
// to distinguish the notes, set a minimum time between them.
|
||||
delay(1.3 * tone_duration.duration_ms);
|
||||
if (config.network.eth_enabled != true) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
const auto &tone_duration = tone_durations[i];
|
||||
#ifdef M5STACK
|
||||
Tone.tone(tone_duration.frequency_khz);
|
||||
delay(tone_duration.duration_ms);
|
||||
Tone.mute();
|
||||
#else
|
||||
tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms);
|
||||
#endif
|
||||
// to distinguish the notes, set a minimum time between them.
|
||||
delay(1.3 * tone_duration.duration_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef M5STACK
|
||||
void playBeep() {
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
#else
|
||||
void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); }
|
||||
#endif
|
||||
|
||||
void playStartMelody() {
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4},
|
||||
{NOTE_B3, DURATION_1_8},
|
||||
{NOTE_B3, DURATION_1_8}};
|
||||
ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8},
|
||||
{NOTE_AS3, DURATION_1_8},
|
||||
{NOTE_CS4, DURATION_1_4}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
|
||||
void playShutdownMelody() {
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4},
|
||||
{NOTE_G3, DURATION_1_8},
|
||||
{NOTE_D3, DURATION_1_8}};
|
||||
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8},
|
||||
{NOTE_AS3, DURATION_1_8},
|
||||
{NOTE_FS3, DURATION_1_4}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
#endif
|
||||
@@ -14,4 +14,5 @@ enum class Cmd {
|
||||
STOP_BOOT_SCREEN,
|
||||
PRINT,
|
||||
START_SHUTDOWN_SCREEN,
|
||||
START_REBOOT_SCREEN,
|
||||
};
|
||||
@@ -25,6 +25,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef RV3028_RTC
|
||||
#include "Melopero_RV3028.h"
|
||||
#endif
|
||||
#ifdef PCF8563_RTC
|
||||
#include "pcf8563.h"
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Version
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -54,76 +62,26 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
/// Convert a preprocessor name into a quoted string and if that string is empty use "unset"
|
||||
#define optstr(s) (xstr(s)[0] ? xstr(s) : "unset")
|
||||
|
||||
#ifdef PORTDUINO
|
||||
|
||||
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
|
||||
|
||||
#elif defined(NRF52_SERIES) // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be
|
||||
// board specific
|
||||
|
||||
//
|
||||
// Standard definitions for NRF52 targets
|
||||
//
|
||||
|
||||
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
|
||||
|
||||
// We bind to the GPS using variant.h instead for this platform (Serial1)
|
||||
|
||||
#define LED_PIN PIN_LED1 // LED1 on nrf52840-DK
|
||||
|
||||
// If the variant filed defines as standard button
|
||||
#ifdef PIN_BUTTON1
|
||||
#define BUTTON_PIN PIN_BUTTON1
|
||||
// Nop definition for these attributes that are specific to ESP32
|
||||
#ifndef EXT_RAM_ATTR
|
||||
#define EXT_RAM_ATTR
|
||||
#endif
|
||||
|
||||
#ifdef PIN_BUTTON2
|
||||
#define BUTTON_PIN_ALT PIN_BUTTON2
|
||||
#ifndef IRAM_ATTR
|
||||
#define IRAM_ATTR
|
||||
#endif
|
||||
|
||||
#ifdef PIN_BUTTON_TOUCH
|
||||
#define BUTTON_PIN_TOUCH PIN_BUTTON_TOUCH
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
//
|
||||
// Standard definitions for ESP32 targets
|
||||
//
|
||||
|
||||
#define HAS_WIFI
|
||||
|
||||
#define GPS_SERIAL_NUM 1
|
||||
#define GPS_RX_PIN 34
|
||||
#ifdef USE_JTAG
|
||||
#define GPS_TX_PIN -1
|
||||
#else
|
||||
#define GPS_TX_PIN 12
|
||||
#ifndef RTC_DATA_ATTR
|
||||
#define RTC_DATA_ATTR
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// LoRa SPI
|
||||
// Feature toggles
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// NRF52 boards will define this in variant.h
|
||||
#ifndef RF95_SCK
|
||||
#define RF95_SCK 5
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 27
|
||||
#define RF95_NSS 18
|
||||
#endif
|
||||
// Disable use of the NTP library and related features
|
||||
// #define DISABLE_NTP
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Standard definitions for !ESP32 targets
|
||||
//
|
||||
|
||||
#ifdef NO_ESP32
|
||||
// Nop definition for these attributes - not used on NRF52
|
||||
#define EXT_RAM_ATTR
|
||||
#define IRAM_ATTR
|
||||
#define RTC_DATA_ATTR
|
||||
#endif
|
||||
// Disable the welcome screen and allow
|
||||
//#define DISABLE_WELCOME_UNSET
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// OLED & Input
|
||||
@@ -136,18 +94,31 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Define this if you know you have that controller or your "SSD1306" misbehaves.
|
||||
//#define USE_SH1106
|
||||
|
||||
// Flip the screen upside down by default as it makes more sense on T-BEAM
|
||||
// devices. Comment this out to not rotate screen 180 degrees.
|
||||
#define SCREEN_FLIP_VERTICALLY
|
||||
|
||||
// Define if screen should be mirrored left to right
|
||||
// #define SCREEN_MIRROR
|
||||
|
||||
// The m5stack I2C Keyboard (also RAK14004)
|
||||
#define CARDKB_ADDR 0x5F
|
||||
|
||||
// The older M5 Faces I2C Keyboard
|
||||
#define FACESKB_ADDR 0x88
|
||||
// -----------------------------------------------------------------------------
|
||||
// SENSOR
|
||||
// -----------------------------------------------------------------------------
|
||||
#define BME_ADDR 0x76
|
||||
#define BME_ADDR_ALTERNATE 0x77
|
||||
#define MCP9808_ADDR 0x18
|
||||
#define INA_ADDR 0x40
|
||||
#define INA_ADDR_ALTERNATE 0x41
|
||||
#define QMC6310_ADDR 0x1C
|
||||
#define QMI8658_ADDR 0x6B
|
||||
#define SHTC3_ADDR 0x70
|
||||
#define LPS22HB_ADDR 0x5C
|
||||
#define LPS22HB_ADDR_ALT 0x5D
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Security
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define ATECC608B_ADDR 0x35
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// GPS
|
||||
@@ -159,97 +130,52 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define GPS_THREAD_INTERVAL 100
|
||||
#endif
|
||||
|
||||
#if defined(TBEAM_V10)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TBEAM
|
||||
|
||||
#elif defined(TBEAM_V07)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TBEAM0p7
|
||||
|
||||
#elif defined(DIY_V1)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_DIY_V1
|
||||
|
||||
#elif defined(RAK_11200)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_RAK11200
|
||||
|
||||
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
|
||||
|
||||
#ifdef HELTEC_V2_0
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V2_0
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HELTEC_V2_1
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V2_1
|
||||
|
||||
#endif
|
||||
|
||||
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32)
|
||||
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V1
|
||||
|
||||
#elif defined(TLORA_V1)
|
||||
|
||||
#define HW_VENDOR HardwareModel_TLORA_V1
|
||||
|
||||
#elif defined(TLORA_V2)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TLORA_V2
|
||||
|
||||
#elif defined(TLORA_V1_3)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TLORA_V1_1p3
|
||||
|
||||
#elif defined(TLORA_V2_1_16)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_TLORA_V2_1_1p6
|
||||
|
||||
#elif defined(GENIEBLOCKS)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_GENIEBLOCKS
|
||||
|
||||
#elif defined(PRIVATE_HW)
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_PRIVATE_HW
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_NRF52840_PCA10056
|
||||
|
||||
// This string must exactly match the case used in release file names or the android updater won't work
|
||||
#define HW_VENDOR HardwareModel_NRF52840DK
|
||||
|
||||
// This board uses 0 to be mean LED on
|
||||
#undef LED_INVERTED
|
||||
#define LED_INVERTED 1
|
||||
|
||||
#elif defined(ARDUINO_NRF52840_PPR)
|
||||
|
||||
#define HW_VENDOR HardwareModel_PPR
|
||||
|
||||
#elif defined(RAK4630)
|
||||
|
||||
#define HW_VENDOR HardwareModel_RAK4631
|
||||
|
||||
#elif defined(TTGO_T_ECHO)
|
||||
|
||||
#define HW_VENDOR HardwareModel_T_ECHO
|
||||
|
||||
#elif NRF52_SERIES
|
||||
|
||||
#define HW_VENDOR HardwareModel_NRF52_UNKNOWN
|
||||
|
||||
#elif PORTDUINO
|
||||
|
||||
#define HW_VENDOR HardwareModel_PORTDUINO
|
||||
|
||||
#endif
|
||||
|
||||
/* Step #1: offer chance for variant-specific defines */
|
||||
#include "variant.h"
|
||||
|
||||
/* Step #2: follow with defines common to the architecture;
|
||||
also enable HAS_ option not specifically disabled by variant.h */
|
||||
#include "architecture.h"
|
||||
|
||||
/* Step #3: mop up with disabled values for HAS_ options not handled by the above two */
|
||||
|
||||
#ifndef HAS_WIFI
|
||||
#define HAS_WIFI 0
|
||||
#endif
|
||||
#ifndef HAS_ETHERNET
|
||||
#define HAS_ETHERNET 0
|
||||
#endif
|
||||
#ifndef HAS_SCREEN
|
||||
#define HAS_SCREEN 0
|
||||
#endif
|
||||
#ifndef HAS_WIRE
|
||||
#define HAS_WIRE 0
|
||||
#endif
|
||||
#ifndef HAS_GPS
|
||||
#define HAS_GPS 0
|
||||
#endif
|
||||
#ifndef HAS_BUTTON
|
||||
#define HAS_BUTTON 0
|
||||
#endif
|
||||
#ifndef HAS_TELEMETRY
|
||||
#define HAS_TELEMETRY 0
|
||||
#endif
|
||||
#ifndef HAS_RADIO
|
||||
#define HAS_RADIO 0
|
||||
#endif
|
||||
#ifndef HAS_RTC
|
||||
#define HAS_RTC 0
|
||||
#endif
|
||||
#ifndef HAS_CPU_SHUTDOWN
|
||||
#define HAS_CPU_SHUTDOWN 0
|
||||
#endif
|
||||
#ifndef HAS_BLUETOOTH
|
||||
#define HAS_BLUETOOTH 0
|
||||
#endif
|
||||
|
||||
#include "RF95Configuration.h"
|
||||
#include "DebugConfiguration.h"
|
||||
|
||||
#ifndef HW_VENDOR
|
||||
#error HW_VENDOR must be defined
|
||||
#endif
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
// Placeholder FIXME
|
||||
@@ -1,80 +0,0 @@
|
||||
#include "../configuration.h"
|
||||
#include "../main.h"
|
||||
#include <Wire.h>
|
||||
|
||||
#ifndef NO_WIRE
|
||||
uint8_t oled_probe(byte addr)
|
||||
{
|
||||
uint8_t r = 0;
|
||||
uint8_t o_probe = 0;
|
||||
Wire.beginTransmission(addr);
|
||||
Wire.write(0x00);
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((int)addr, 1);
|
||||
if (Wire.available()) {
|
||||
r = Wire.read();
|
||||
}
|
||||
r &= 0x0f;
|
||||
if (r == 0x08) {
|
||||
o_probe = 2; // SH1106
|
||||
} else if ( r == 0x03 || r == 0x06 || r == 0x07) {
|
||||
o_probe = 1; // SSD1306
|
||||
}
|
||||
DEBUG_MSG("0x%x subtype probed\n", r);
|
||||
return o_probe;
|
||||
}
|
||||
|
||||
void scanI2Cdevice(void)
|
||||
{
|
||||
byte err, addr;
|
||||
int nDevices = 0;
|
||||
for (addr = 1; addr < 127; addr++) {
|
||||
Wire.beginTransmission(addr);
|
||||
err = Wire.endTransmission();
|
||||
if (err == 0) {
|
||||
DEBUG_MSG("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){
|
||||
DEBUG_MSG("ssd1306 display found\n");
|
||||
} else if (screen_model == 2){
|
||||
DEBUG_MSG("sh1106 display found\n");
|
||||
} else {
|
||||
DEBUG_MSG("unknown display found\n");
|
||||
}
|
||||
}
|
||||
if (addr == CARDKB_ADDR) {
|
||||
cardkb_found = addr;
|
||||
DEBUG_MSG("m5 cardKB found\n");
|
||||
}
|
||||
if (addr == FACESKB_ADDR) {
|
||||
faceskb_found = addr;
|
||||
DEBUG_MSG("m5 Faces found\n");
|
||||
}
|
||||
if (addr == ST7567_ADDRESS) {
|
||||
screen_found = addr;
|
||||
DEBUG_MSG("st7567 display found\n");
|
||||
}
|
||||
#ifdef AXP192_SLAVE_ADDRESS
|
||||
if (addr == AXP192_SLAVE_ADDRESS) {
|
||||
axp192_found = true;
|
||||
DEBUG_MSG("axp192 PMU found\n");
|
||||
}
|
||||
#endif
|
||||
} else if (err == 4) {
|
||||
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (nDevices == 0)
|
||||
DEBUG_MSG("No I2C devices found\n");
|
||||
else
|
||||
DEBUG_MSG("done\n");
|
||||
}
|
||||
#else
|
||||
void scanI2Cdevice(void) {}
|
||||
#endif
|
||||
60
src/detect/einkScan.h
Normal file
60
src/detect/einkScan.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "../configuration.h"
|
||||
|
||||
#ifdef RAK4630
|
||||
#include "../main.h"
|
||||
#include <SPI.h>
|
||||
|
||||
void d_writeCommand(uint8_t c)
|
||||
{
|
||||
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, LOW);
|
||||
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW);
|
||||
SPI1.transfer(c);
|
||||
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH);
|
||||
if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, HIGH);
|
||||
SPI1.endTransaction();
|
||||
}
|
||||
|
||||
void d_writeData(uint8_t d)
|
||||
{
|
||||
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW);
|
||||
SPI1.transfer(d);
|
||||
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH);
|
||||
SPI1.endTransaction();
|
||||
}
|
||||
|
||||
unsigned long d_waitWhileBusy(uint16_t busy_time)
|
||||
{
|
||||
if (PIN_EINK_BUSY >= 0)
|
||||
{
|
||||
delay(1); // add some margin to become active
|
||||
unsigned long start = micros();
|
||||
while (1)
|
||||
{
|
||||
if (digitalRead(PIN_EINK_BUSY) != HIGH) break;
|
||||
delay(1);
|
||||
if (digitalRead(PIN_EINK_BUSY) != HIGH) break;
|
||||
if (micros() - start > 10000000) break;
|
||||
}
|
||||
unsigned long elapsed = micros() - start;
|
||||
(void) start;
|
||||
return elapsed;
|
||||
}
|
||||
else return busy_time;
|
||||
}
|
||||
|
||||
void scanEInkDevice(void)
|
||||
{
|
||||
SPI1.begin();
|
||||
d_writeCommand(0x22);
|
||||
d_writeData(0x83);
|
||||
d_writeCommand(0x20);
|
||||
eink_found = (d_waitWhileBusy(150) > 0) ? true : false;
|
||||
if(eink_found)
|
||||
DEBUG_MSG("EInk display found\n");
|
||||
else
|
||||
DEBUG_MSG("EInk display not found\n");
|
||||
SPI1.end();
|
||||
}
|
||||
#endif
|
||||
222
src/detect/i2cScan.h
Normal file
222
src/detect/i2cScan.h
Normal file
@@ -0,0 +1,222 @@
|
||||
#include "../configuration.h"
|
||||
#include "../main.h"
|
||||
#include <Wire.h>
|
||||
#include "mesh/generated/telemetry.pb.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()
|
||||
{
|
||||
#ifndef ARCH_PORTDUINO
|
||||
atecc.readConfigZone(false);
|
||||
|
||||
DEBUG_MSG("ATECC608B Serial Number: ");
|
||||
for (int i = 0 ; i < 9 ; i++) {
|
||||
DEBUG_MSG("%02x",atecc.serialNumber[i]);
|
||||
}
|
||||
|
||||
DEBUG_MSG(", Rev Number: ");
|
||||
for (int i = 0 ; i < 4 ; i++) {
|
||||
DEBUG_MSG("%02x",atecc.revisionNumber[i]);
|
||||
}
|
||||
DEBUG_MSG("\n");
|
||||
|
||||
DEBUG_MSG("ATECC608B Config %s",atecc.configLockStatus ? "Locked" : "Unlocked");
|
||||
DEBUG_MSG(", Data %s",atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
|
||||
DEBUG_MSG(", Slot 0 %s\n",atecc.slot0LockStatus ? "Locked" : "Unlocked");
|
||||
|
||||
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
|
||||
if (atecc.generatePublicKey() == false) {
|
||||
DEBUG_MSG("ATECC608B Error generating public key\n");
|
||||
} else {
|
||||
DEBUG_MSG("ATECC608B Public Key: ");
|
||||
for (int i = 0 ; i < 64 ; i++) {
|
||||
DEBUG_MSG("%02x",atecc.publicKey64Bytes[i]);
|
||||
}
|
||||
DEBUG_MSG("\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);
|
||||
DEBUG_MSG("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));
|
||||
DEBUG_MSG("0x%x subtype probed in %i tries \n", r, c);
|
||||
return o_probe;
|
||||
}
|
||||
|
||||
void scanI2Cdevice(void)
|
||||
{
|
||||
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) {
|
||||
DEBUG_MSG("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){
|
||||
DEBUG_MSG("ssd1306 display found\n");
|
||||
} else if (screen_model == 2){
|
||||
DEBUG_MSG("sh1106 display found\n");
|
||||
} else {
|
||||
DEBUG_MSG("unknown display found\n");
|
||||
}
|
||||
}
|
||||
#ifndef ARCH_PORTDUINO
|
||||
if (addr == ATECC608B_ADDR){
|
||||
keystore_found = addr;
|
||||
if (atecc.begin(keystore_found) == true) {
|
||||
DEBUG_MSG("ATECC608B initialized\n");
|
||||
} else {
|
||||
DEBUG_MSG("ATECC608B initialization failed\n");
|
||||
}
|
||||
printATECCInfo();
|
||||
}
|
||||
#endif
|
||||
#ifdef RV3028_RTC
|
||||
if (addr == RV3028_RTC){
|
||||
rtc_found = addr;
|
||||
DEBUG_MSG("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;
|
||||
DEBUG_MSG("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
|
||||
DEBUG_MSG("RAK14004 found\n");
|
||||
kb_model = 0x02;
|
||||
} else {
|
||||
DEBUG_MSG("m5 cardKB found\n");
|
||||
kb_model = 0x00;
|
||||
}
|
||||
}
|
||||
if (addr == ST7567_ADDRESS) {
|
||||
screen_found = addr;
|
||||
DEBUG_MSG("st7567 display found\n");
|
||||
}
|
||||
#ifdef HAS_PMU
|
||||
if (addr == XPOWERS_AXP192_AXP2101_ADDRESS) {
|
||||
pmu_found = true;
|
||||
DEBUG_MSG("axp192/axp2101 PMU found\n");
|
||||
}
|
||||
#endif
|
||||
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
|
||||
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
|
||||
if (registerValue == 0x61) {
|
||||
DEBUG_MSG("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr;
|
||||
} else if (registerValue == 0x60) {
|
||||
DEBUG_MSG("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr;
|
||||
} else {
|
||||
DEBUG_MSG("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_BMP280] = addr;
|
||||
}
|
||||
}
|
||||
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
|
||||
registerValue = getRegisterValue(addr, 0xFE, 2);
|
||||
DEBUG_MSG("Register MFG_UID: 0x%x\n", registerValue);
|
||||
if (registerValue == 0x5449) {
|
||||
DEBUG_MSG("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_INA260] = addr;
|
||||
} else { // Assume INA219 if INA260 ID is not found
|
||||
DEBUG_MSG("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_INA219] = addr;
|
||||
}
|
||||
}
|
||||
if (addr == MCP9808_ADDR) {
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
|
||||
DEBUG_MSG("MCP9808 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
}
|
||||
if (addr == QMC6310_ADDR) {
|
||||
DEBUG_MSG("QMC6310 3-Axis magnetic sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMC6310] = addr;
|
||||
}
|
||||
if (addr == QMI8658_ADDR) {
|
||||
DEBUG_MSG("QMI8658 6-Axis inertial measurement sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658] = addr;
|
||||
}
|
||||
if (addr == SHTC3_ADDR) {
|
||||
DEBUG_MSG("SHTC3 sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_SHTC3] = addr;
|
||||
}
|
||||
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
|
||||
DEBUG_MSG("LPS22HB sensor found at address 0x%x\n", (uint8_t)addr);
|
||||
nodeTelemetrySensorsMap[TelemetrySensorType_LPS22] = addr;
|
||||
}
|
||||
} else if (err == 4) {
|
||||
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (nDevices == 0)
|
||||
DEBUG_MSG("No I2C devices found\n");
|
||||
else
|
||||
DEBUG_MSG("%i I2C devices found\n",nDevices);
|
||||
}
|
||||
#else
|
||||
void scanI2Cdevice(void) {}
|
||||
#endif
|
||||
@@ -8,4 +8,4 @@
|
||||
#define RECORD_CRITICALERROR(code) recordCriticalError(code, __LINE__, __FILE__)
|
||||
|
||||
/// Record an error that should be reported via analytics
|
||||
void recordCriticalError(CriticalErrorCode code = CriticalErrorCode_Unspecified, uint32_t address = 0, const char *filename = NULL);
|
||||
void recordCriticalError(CriticalErrorCode code = CriticalErrorCode_UNSPECIFIED, uint32_t address = 0, const char *filename = NULL);
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "../concurrency/LockGuard.h"
|
||||
#include "../graphics/Screen.h"
|
||||
#include "../main.h"
|
||||
#include "BluetoothSoftwareUpdate.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "configuration.h"
|
||||
#include "nimble/BluetoothUtil.h"
|
||||
|
||||
#include <CRC32.h>
|
||||
#include <Update.h>
|
||||
|
||||
int16_t updateResultHandle = -1;
|
||||
|
||||
static CRC32 crc;
|
||||
|
||||
static uint32_t updateExpectedSize, updateActualSize;
|
||||
static uint8_t update_result;
|
||||
static uint8_t update_region;
|
||||
|
||||
static concurrency::Lock *updateLock;
|
||||
|
||||
/// Handle writes & reads to total size
|
||||
int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
concurrency::LockGuard g(updateLock);
|
||||
|
||||
// Check if there is enough to OTA Update
|
||||
chr_readwrite32le(&updateExpectedSize, ctxt);
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR && updateExpectedSize != 0) {
|
||||
updateActualSize = 0;
|
||||
crc.reset();
|
||||
if (Update.isRunning())
|
||||
Update.abort();
|
||||
bool canBegin = Update.begin(updateExpectedSize, update_region);
|
||||
DEBUG_MSG("Setting region %d update size %u, result %d\n", update_region, updateExpectedSize, canBegin);
|
||||
if (!canBegin) {
|
||||
// Indicate failure by forcing the size to 0 (client will read it back)
|
||||
updateExpectedSize = 0;
|
||||
} else {
|
||||
// This totally breaks abstraction to up up into the app layer for this, but quick hack to make sure we only
|
||||
// talk to one service during the sw update.
|
||||
// DEBUG_MSG("FIXME, crufty shutdown of mesh bluetooth for sw update.");
|
||||
// void stopMeshBluetoothService();
|
||||
// stopMeshBluetoothService();
|
||||
|
||||
screen->startFirmwareUpdateScreen();
|
||||
if (RadioLibInterface::instance)
|
||||
RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we
|
||||
// are writing flash - shut the radio off during updates
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_BLOCKSIZE_FOR_BT 512
|
||||
|
||||
/// Handle writes to data
|
||||
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
concurrency::LockGuard g(updateLock);
|
||||
|
||||
static uint8_t
|
||||
data[MAX_BLOCKSIZE_FOR_BT]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
|
||||
|
||||
uint16_t len = 0;
|
||||
|
||||
auto rc = ble_hs_mbuf_to_flat(ctxt->om, data, sizeof(data), &len);
|
||||
assert(rc == 0);
|
||||
|
||||
// DEBUG_MSG("Writing %u\n", len);
|
||||
crc.update(data, len);
|
||||
Update.write(data, len);
|
||||
updateActualSize += len;
|
||||
powerFSM.trigger(EVENT_FIRMWARE_UPDATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Handle writes to crc32
|
||||
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
concurrency::LockGuard g(updateLock);
|
||||
uint32_t expectedCRC = 0;
|
||||
chr_readwrite32le(&expectedCRC, ctxt);
|
||||
|
||||
uint32_t actualCRC = crc.finalize();
|
||||
DEBUG_MSG("expected CRC %u\n", expectedCRC);
|
||||
|
||||
uint8_t result = 0xff;
|
||||
|
||||
if (updateActualSize != updateExpectedSize) {
|
||||
DEBUG_MSG("Expected %u bytes, but received %u bytes!\n", updateExpectedSize, updateActualSize);
|
||||
result = 0xe1; // FIXME, use real error codes
|
||||
} else if (actualCRC != expectedCRC) // Check the CRC before asking the update to happen.
|
||||
{
|
||||
DEBUG_MSG("Invalid CRC! expected=%u, actual=%u\n", expectedCRC, actualCRC);
|
||||
result = 0xe0; // FIXME, use real error codes
|
||||
} else {
|
||||
if (Update.end()) {
|
||||
if (update_region == U_SPIFFS) {
|
||||
DEBUG_MSG("Filesystem updated!\n");
|
||||
nodeDB.saveToDisk(); // Since we just wiped the filesystem, we need to save our current state
|
||||
} else {
|
||||
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
|
||||
rebootAtMsec = millis() + 5000;
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError());
|
||||
}
|
||||
result = Update.getError();
|
||||
}
|
||||
|
||||
if (RadioLibInterface::instance)
|
||||
RadioLibInterface::instance->startReceive(); // Resume radio
|
||||
|
||||
assert(updateResultHandle >= 0);
|
||||
update_result = result;
|
||||
DEBUG_MSG("BLE notify update result\n");
|
||||
auto res = ble_gattc_notify(curConnectionHandle, updateResultHandle);
|
||||
assert(res == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
return chr_readwrite8(&update_result, sizeof(update_result), ctxt);
|
||||
}
|
||||
|
||||
int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
return chr_readwrite8(&update_region, sizeof(update_region), ctxt);
|
||||
}
|
||||
|
||||
/*
|
||||
See bluetooth-api.md
|
||||
|
||||
*/
|
||||
void reinitUpdateService()
|
||||
{
|
||||
if (!updateLock)
|
||||
updateLock = new concurrency::Lock();
|
||||
|
||||
auto res = ble_gatts_count_cfg(gatt_update_svcs); // assigns handles? see docstring for note about clearing the handle list
|
||||
// before calling SLEEP SUPPORT
|
||||
assert(res == 0);
|
||||
|
||||
res = ble_gatts_add_svcs(gatt_update_svcs);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "nimble/NimbleDefs.h"
|
||||
|
||||
void reinitUpdateService();
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
extern const struct ble_gatt_svc_def gatt_update_svcs[];
|
||||
|
||||
extern const ble_uuid128_t update_result_uuid, update_region_uuid;
|
||||
|
||||
extern int16_t updateResultHandle;
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
@@ -1,262 +0,0 @@
|
||||
#ifdef USE_NEW_ESP32_BLUETOOTH
|
||||
|
||||
#include "configuration.h"
|
||||
#include "ESP32Bluetooth.h"
|
||||
#include "BluetoothCommon.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "sleep.h"
|
||||
#include "main.h"
|
||||
#include "mesh/PhoneAPI.h"
|
||||
#include "mesh/mesh-pb-constants.h"
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
//static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
|
||||
//static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
|
||||
//static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16));
|
||||
//static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16));
|
||||
|
||||
//static BLEDis bledis; // DIS (Device Information Service) helper class instance
|
||||
//static BLEBas blebas; // BAS (Battery Service) helper class instance
|
||||
//static BLEDfu bledfu; // DFU software update helper service
|
||||
|
||||
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
|
||||
// proccess at once
|
||||
// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
|
||||
static uint8_t fromRadioBytes[FromRadio_size];
|
||||
static uint8_t toRadioBytes[ToRadio_size];
|
||||
|
||||
static bool bleConnected;
|
||||
|
||||
NimBLECharacteristic *FromNumCharacteristic;
|
||||
NimBLEServer *bleServer;
|
||||
|
||||
static bool passkeyShowing;
|
||||
static uint32_t doublepressed;
|
||||
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
void BluetoothPhoneAPI::onNowHasData(uint32_t fromRadioNum)
|
||||
{
|
||||
PhoneAPI::onNowHasData(fromRadioNum);
|
||||
|
||||
DEBUG_MSG("BLE notify fromNum\n");
|
||||
//fromNum.notify32(fromRadioNum);
|
||||
|
||||
uint8_t val[4];
|
||||
put_le32(val, fromRadioNum);
|
||||
|
||||
std::string fromNumByteString(&val[0], &val[0] + sizeof(val));
|
||||
|
||||
FromNumCharacteristic->setValue(fromNumByteString);
|
||||
FromNumCharacteristic->notify();
|
||||
}
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
bool BluetoothPhoneAPI::checkIsConnected() {
|
||||
if (bleServer && bleServer->getConnectedCount() > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PhoneAPI *bluetoothPhoneAPI;
|
||||
|
||||
class ESP32BluetoothToRadioCallback : public NimBLECharacteristicCallbacks {
|
||||
virtual void onWrite(NimBLECharacteristic *pCharacteristic) {
|
||||
DEBUG_MSG("To Radio onwrite\n");
|
||||
auto valueString = pCharacteristic->getValue();
|
||||
|
||||
bluetoothPhoneAPI->handleToRadio(reinterpret_cast<const uint8_t*>(&valueString[0]), pCharacteristic->getDataLength());
|
||||
}
|
||||
};
|
||||
|
||||
class ESP32BluetoothFromRadioCallback : public NimBLECharacteristicCallbacks {
|
||||
virtual void onRead(NimBLECharacteristic *pCharacteristic) {
|
||||
DEBUG_MSG("From Radio onread\n");
|
||||
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
|
||||
|
||||
std::string fromRadioByteString(fromRadioBytes, fromRadioBytes + numBytes);
|
||||
|
||||
pCharacteristic->setValue(fromRadioByteString);
|
||||
}
|
||||
};
|
||||
|
||||
class ESP32BluetoothServerCallback : public NimBLEServerCallbacks {
|
||||
virtual uint32_t onPassKeyRequest() {
|
||||
|
||||
uint32_t passkey = 0;
|
||||
|
||||
if (doublepressed > 0 && (doublepressed + (30 * 1000)) > millis()) {
|
||||
DEBUG_MSG("User has overridden passkey\n");
|
||||
passkey = defaultBLEPin;
|
||||
} else {
|
||||
DEBUG_MSG("Using random passkey\n");
|
||||
passkey = random(
|
||||
100000, 999999); // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
|
||||
}
|
||||
DEBUG_MSG("*** Enter passkey %d on the peer side ***\n", passkey);
|
||||
|
||||
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
||||
screen->startBluetoothPinScreen(passkey);
|
||||
passkeyShowing = true;
|
||||
|
||||
return passkey;
|
||||
}
|
||||
|
||||
virtual void onAuthenticationComplete(ble_gap_conn_desc *desc) {
|
||||
DEBUG_MSG("BLE authentication complete\n");
|
||||
|
||||
if (passkeyShowing) {
|
||||
passkeyShowing = false;
|
||||
screen->stopBluetoothPinScreen();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static ESP32BluetoothToRadioCallback *toRadioCallbacks;
|
||||
static ESP32BluetoothFromRadioCallback *fromRadioCallbacks;
|
||||
|
||||
void ESP32Bluetooth::shutdown()
|
||||
{
|
||||
// Shutdown bluetooth for minimum power draw
|
||||
DEBUG_MSG("Disable bluetooth\n");
|
||||
//Bluefruit.Advertising.stop();
|
||||
}
|
||||
|
||||
void ESP32Bluetooth::setup()
|
||||
{
|
||||
// Initialise the Bluefruit module
|
||||
DEBUG_MSG("Initialise the ESP32 bluetooth module\n");
|
||||
//Bluefruit.autoConnLed(false);
|
||||
//Bluefruit.begin();
|
||||
|
||||
// Set the advertised device name (keep it short!)
|
||||
//Bluefruit.setName(getDeviceName());
|
||||
|
||||
// Set the connect/disconnect callback handlers
|
||||
//Bluefruit.Periph.setConnectCallback(connect_callback);
|
||||
//Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
|
||||
|
||||
// Configure and Start the Device Information Service
|
||||
DEBUG_MSG("Configuring the Device Information Service\n");
|
||||
// FIXME, we should set a mfg string based on our HW_VENDOR enum
|
||||
// bledis.setManufacturer(HW_VENDOR);
|
||||
//bledis.setModel(optstr(HW_VERSION));
|
||||
//bledis.setFirmwareRev(optstr(APP_VERSION));
|
||||
//bledis.begin();
|
||||
|
||||
// Start the BLE Battery Service and set it to 100%
|
||||
//DEBUG_MSG("Configuring the Battery Service\n");
|
||||
//blebas.begin();
|
||||
//blebas.write(0); // Unknown battery level for now
|
||||
|
||||
//bledfu.begin(); // Install the DFU helper
|
||||
|
||||
// Setup the Heart Rate Monitor service using
|
||||
// BLEService and BLECharacteristic classes
|
||||
DEBUG_MSG("Configuring the Mesh bluetooth service\n");
|
||||
//setupMeshService();
|
||||
|
||||
// Supposedly debugging works with soft device if you disable advertising
|
||||
//if (isSoftDeviceAllowed) {
|
||||
// Setup the advertising packet(s)
|
||||
// DEBUG_MSG("Setting up the advertising payload(s)\n");
|
||||
// startAdv();
|
||||
|
||||
// DEBUG_MSG("Advertising\n");
|
||||
//}
|
||||
|
||||
//NimBLEDevice::deleteAllBonds();
|
||||
|
||||
NimBLEDevice::init(getDeviceName());
|
||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
|
||||
|
||||
NimBLEDevice::setSecurityAuth(true, true, true);
|
||||
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
|
||||
bleServer = NimBLEDevice::createServer();
|
||||
|
||||
ESP32BluetoothServerCallback *serverCallbacks = new ESP32BluetoothServerCallback();
|
||||
bleServer->setCallbacks(serverCallbacks);
|
||||
|
||||
NimBLEService *bleService = bleServer->createService(MESH_SERVICE_UUID);
|
||||
//NimBLECharacteristic *pNonSecureCharacteristic = bleService->createCharacteristic("1234", NIMBLE_PROPERTY::READ );
|
||||
//NimBLECharacteristic *pSecureCharacteristic = bleService->createCharacteristic("1235", NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::READ_AUTHEN);
|
||||
|
||||
//define the characteristics that the app is looking for
|
||||
NimBLECharacteristic *ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
NimBLECharacteristic *FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC);
|
||||
FromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC);
|
||||
|
||||
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
||||
|
||||
toRadioCallbacks = new ESP32BluetoothToRadioCallback();
|
||||
ToRadioCharacteristic->setCallbacks(toRadioCallbacks);
|
||||
|
||||
fromRadioCallbacks = new ESP32BluetoothFromRadioCallback();
|
||||
FromRadioCharacteristic->setCallbacks(fromRadioCallbacks);
|
||||
|
||||
//uint8_t val[4];
|
||||
//uint32_t zero = 0;
|
||||
//put_le32(val, zero);
|
||||
//std::string fromNumByteString(&val[0], &val[0] + sizeof(val));
|
||||
//FromNumCharacteristic->setValue(fromNumByteString);
|
||||
|
||||
bleService->start();
|
||||
//pNonSecureCharacteristic->setValue("Hello Non Secure BLE");
|
||||
//pSecureCharacteristic->setValue("Hello Secure BLE");
|
||||
|
||||
//FromRadioCharacteristic->setValue("FromRadioString");
|
||||
//ToRadioCharacteristic->setCallbacks()
|
||||
|
||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
|
||||
pAdvertising->start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Given a level between 0-100, update the BLE attribute
|
||||
void updateBatteryLevel(uint8_t level)
|
||||
{
|
||||
//blebas.write(level);
|
||||
}
|
||||
|
||||
void ESP32Bluetooth::clearBonds()
|
||||
{
|
||||
DEBUG_MSG("Clearing bluetooth bonds!\n");
|
||||
//bond_print_list(BLE_GAP_ROLE_PERIPH);
|
||||
//bond_print_list(BLE_GAP_ROLE_CENTRAL);
|
||||
|
||||
//Bluefruit.Periph.clearBonds();
|
||||
//Bluefruit.Central.clearBonds();
|
||||
|
||||
}
|
||||
|
||||
void clearNVS() {
|
||||
NimBLEDevice::deleteAllBonds();
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void disablePin() {
|
||||
DEBUG_MSG("User Override, disabling bluetooth pin requirement\n");
|
||||
// keep track of when it was pressed, so we know it was within X seconds
|
||||
|
||||
// Flash the LED
|
||||
setLed(true);
|
||||
delay(100);
|
||||
setLed(false);
|
||||
delay(100);
|
||||
setLed(true);
|
||||
delay(100);
|
||||
setLed(false);
|
||||
delay(100);
|
||||
setLed(true);
|
||||
delay(100);
|
||||
setLed(false);
|
||||
|
||||
doublepressed = millis();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifdef USE_NEW_ESP32_BLUETOOTH
|
||||
|
||||
#pragma once
|
||||
|
||||
extern uint16_t fromNumValHandle;
|
||||
|
||||
class BluetoothPhoneAPI : public PhoneAPI
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum) override;
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() override;
|
||||
};
|
||||
|
||||
extern PhoneAPI *bluetoothPhoneAPI;
|
||||
|
||||
class ESP32Bluetooth
|
||||
{
|
||||
public:
|
||||
void setup();
|
||||
void shutdown();
|
||||
void clearBonds();
|
||||
};
|
||||
|
||||
void setBluetoothEnable(bool on);
|
||||
void clearNVS();
|
||||
void disablePin();
|
||||
|
||||
#endif
|
||||
@@ -1,73 +0,0 @@
|
||||
#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
#include "BluetoothSoftwareUpdate.h"
|
||||
|
||||
// NRF52 wants these constants as byte arrays
|
||||
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
|
||||
|
||||
// "cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30"
|
||||
const ble_uuid128_t update_service_uuid =
|
||||
BLE_UUID128_INIT(0x30, 0xee, 0x44, 0x31, 0x2e, 0x44, 0xbb, 0xbd, 0x0d, 0x4c, 0x4c, 0xa8, 0x0b, 0x9a, 0x0b, 0xcb);
|
||||
|
||||
// "e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e" write|read
|
||||
const ble_uuid128_t update_size_uuid =
|
||||
BLE_UUID128_INIT(0x1e, 0x8e, 0xea, 0xdb, 0xe1, 0xf0, 0xa1, 0x95, 0x6f, 0x4a, 0x01, 0xa3, 0xc0, 0xd9, 0x4d, 0xe7);
|
||||
|
||||
// "e272ebac-d463-4b98-bc84-5cc1a39ee517" write
|
||||
const ble_uuid128_t update_data_uuid =
|
||||
BLE_UUID128_INIT(0x17, 0xe5, 0x9e, 0xa3, 0xc1, 0x5c, 0x84, 0xbc, 0x98, 0x4b, 0x63, 0xd4, 0xac, 0xeb, 0x72, 0xe2);
|
||||
|
||||
// "4826129c-c22a-43a3-b066-ce8f0d5bacc6" write
|
||||
const ble_uuid128_t update_crc32_uuid =
|
||||
BLE_UUID128_INIT(0xc6, 0xac, 0x5b, 0x0d, 0x8f, 0xce, 0x66, 0xb0, 0xa3, 0x43, 0x2a, 0xc2, 0x9c, 0x12, 0x26, 0x48);
|
||||
|
||||
// "5e134862-7411-4424-ac4a-210937432c77" read|notify
|
||||
const ble_uuid128_t update_result_uuid =
|
||||
BLE_UUID128_INIT(0x77, 0x2c, 0x43, 0x37, 0x09, 0x21, 0x4a, 0xac, 0x24, 0x44, 0x11, 0x74, 0x62, 0x48, 0x13, 0x5e);
|
||||
|
||||
// "5e134862-7411-4424-ac4a-210937432c67" write
|
||||
const ble_uuid128_t update_region_uuid =
|
||||
BLE_UUID128_INIT(0x67, 0x2c, 0x43, 0x37, 0x09, 0x21, 0x4a, 0xac, 0x24, 0x44, 0x11, 0x74, 0x62, 0x48, 0x13, 0x5e);
|
||||
|
||||
const struct ble_gatt_svc_def gatt_update_svcs[] = {
|
||||
{
|
||||
/*** Service: Security test. */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &update_service_uuid.u,
|
||||
.characteristics =
|
||||
(struct ble_gatt_chr_def[]){{
|
||||
.uuid = &update_size_uuid.u,
|
||||
.access_cb = update_size_callback,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_READ |
|
||||
BLE_GATT_CHR_F_READ_AUTHEN,
|
||||
},
|
||||
{
|
||||
.uuid = &update_data_uuid.u,
|
||||
.access_cb = update_data_callback,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
},
|
||||
{
|
||||
.uuid = &update_crc32_uuid.u,
|
||||
.access_cb = update_crc32_callback,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
},
|
||||
{
|
||||
.uuid = &update_result_uuid.u,
|
||||
.access_cb = update_result_callback,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY,
|
||||
},
|
||||
{
|
||||
.uuid = &update_region_uuid.u,
|
||||
.access_cb = update_region_callback,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
},
|
||||
{
|
||||
0, /* No more characteristics in this service. */
|
||||
}},
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH
|
||||
411
src/gps/GPS.cpp
411
src/gps/GPS.cpp
@@ -1,7 +1,7 @@
|
||||
#include "configuration.h"
|
||||
#include "GPS.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "sleep.h"
|
||||
#include <assert.h>
|
||||
|
||||
@@ -16,32 +16,235 @@ HardwareSerial *GPS::_serial_gps = &Serial1;
|
||||
HardwareSerial *GPS::_serial_gps = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef GPS_I2C_ADDRESS
|
||||
uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS;
|
||||
#else
|
||||
uint8_t GPS::i2cAddress = 0;
|
||||
#endif
|
||||
|
||||
GPS *gps;
|
||||
|
||||
/// Multiple GPS instances might use the same serial port (in sequence), but we can
|
||||
/// only init that port once.
|
||||
static bool didSerialInit;
|
||||
|
||||
bool GPS::getACK(uint8_t c, uint8_t i) {
|
||||
uint8_t b;
|
||||
uint8_t ack = 0;
|
||||
const uint8_t ackP[2] = {c, i};
|
||||
uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
unsigned long startTime = millis();
|
||||
|
||||
for (int j = 2; j < 6; j++) {
|
||||
buf[8] += buf[j];
|
||||
buf[9] += buf[8];
|
||||
}
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
buf[6 + j] = ackP[j];
|
||||
buf[8] += buf[6 + j];
|
||||
buf[9] += buf[8];
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (ack > 9) {
|
||||
return true;
|
||||
}
|
||||
if (millis() - startTime > 1000) {
|
||||
return false;
|
||||
}
|
||||
if (_serial_gps->available()) {
|
||||
b = _serial_gps->read();
|
||||
if (b == buf[ack]) {
|
||||
ack++;
|
||||
}
|
||||
else {
|
||||
ack = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @note New method, this method can wait for the specified class and message ID, and return the payload
|
||||
* @param *buffer: The message buffer, if there is a response payload message, it will be returned through the buffer parameter
|
||||
* @param size: size of buffer
|
||||
* @param requestedClass: request class constant
|
||||
* @param requestedID: request message ID constant
|
||||
* @retval length of payload message
|
||||
*/
|
||||
int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID)
|
||||
{
|
||||
uint16_t ubxFrameCounter = 0;
|
||||
uint32_t startTime = millis();
|
||||
uint16_t needRead;
|
||||
|
||||
while (millis() - startTime < 800) {
|
||||
while (_serial_gps->available()) {
|
||||
int c = _serial_gps->read();
|
||||
switch (ubxFrameCounter) {
|
||||
case 0:
|
||||
//ubxFrame 'μ'
|
||||
if (c == 0xB5) {
|
||||
ubxFrameCounter++;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
//ubxFrame 'b'
|
||||
if (c == 0x62) {
|
||||
ubxFrameCounter++;
|
||||
} else {
|
||||
ubxFrameCounter = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
//Class
|
||||
if (c == requestedClass) {
|
||||
ubxFrameCounter++;
|
||||
} else {
|
||||
ubxFrameCounter = 0;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
//Message ID
|
||||
if (c == requestedID) {
|
||||
ubxFrameCounter++;
|
||||
} else {
|
||||
ubxFrameCounter = 0;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
//Payload lenght lsb
|
||||
needRead = c;
|
||||
ubxFrameCounter++;
|
||||
break;
|
||||
case 5:
|
||||
//Payload lenght msb
|
||||
needRead |= (c << 8);
|
||||
ubxFrameCounter++;
|
||||
break;
|
||||
case 6:
|
||||
// Check for buffer overflow
|
||||
if (needRead >= size) {
|
||||
ubxFrameCounter = 0;
|
||||
break;
|
||||
}
|
||||
if (_serial_gps->readBytes(buffer, needRead) != needRead) {
|
||||
ubxFrameCounter = 0;
|
||||
} else {
|
||||
// return payload lenght
|
||||
return needRead;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool GPS::setupGPS()
|
||||
{
|
||||
if (_serial_gps && !didSerialInit) {
|
||||
didSerialInit = true;
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// In esp32 framework, setRxBufferSize needs to be initialized before Serial
|
||||
_serial_gps->setRxBufferSize(2048); // the default is 256
|
||||
#endif
|
||||
|
||||
// ESP32 has a special set of parameters vs other arduino ports
|
||||
#if defined(GPS_RX_PIN) && !defined(NO_ESP32)
|
||||
#if defined(GPS_RX_PIN) && defined(ARCH_ESP32)
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
|
||||
#else
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#endif
|
||||
#ifndef NO_ESP32
|
||||
_serial_gps->setRxBufferSize(2048); // the default is 256
|
||||
#endif
|
||||
|
||||
/*
|
||||
* T-Beam-S3-Core will be preset to use gps Probe here, and other boards will not be changed first
|
||||
*/
|
||||
gnssModel = probe();
|
||||
|
||||
if(gnssModel == GNSS_MODEL_MTK){
|
||||
/*
|
||||
* t-beam-s3-core uses the same L76K GNSS module as t-echo.
|
||||
* Unlike t-echo, L76K uses 9600 baud rate for communication by default.
|
||||
* */
|
||||
// _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);
|
||||
|
||||
// Initialize the L76K Chip, use GPS + GLONASS
|
||||
_serial_gps->write("$PCAS04,5*1C\r\n");
|
||||
delay(250);
|
||||
// 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");
|
||||
delay(250);
|
||||
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
|
||||
_serial_gps->write("$PCAS11,3*1E\r\n");
|
||||
delay(250);
|
||||
|
||||
}else if(gnssModel == GNSS_MODEL_UBLOX){
|
||||
|
||||
/*
|
||||
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
|
||||
|
||||
// Set the UART port to output NMEA only
|
||||
byte _message_nmea[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00,
|
||||
0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xAF};
|
||||
_serial_gps->write(_message_nmea, sizeof(_message_nmea));
|
||||
if (!getACK(0x06, 0x00)) {
|
||||
DEBUG_MSG("WARNING: Unable to enable NMEA Mode.\n");
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
// ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid
|
||||
|
||||
// disable GGL
|
||||
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A};
|
||||
_serial_gps->write(_message_GGL, sizeof(_message_GGL));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to disable NMEA GGL.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable GSA
|
||||
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41};
|
||||
_serial_gps->write(_message_GSA, sizeof(_message_GSA));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to disable NMEA GSA.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable GSV
|
||||
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48};
|
||||
_serial_gps->write(_message_GSV, sizeof(_message_GSV));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to disable NMEA GSV.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable VTG
|
||||
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56};
|
||||
_serial_gps->write(_message_VTG, sizeof(_message_VTG));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to disable NMEA VTG.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// enable RMC
|
||||
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54};
|
||||
_serial_gps->write(_message_RMC, sizeof(_message_RMC));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to enable NMEA RMC.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// enable GGA
|
||||
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38};
|
||||
_serial_gps->write(_message_GGA, sizeof(_message_GGA));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
DEBUG_MSG("WARNING: Unable to enable NMEA GGA.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -76,11 +279,19 @@ bool GPS::setup()
|
||||
GPS::~GPS()
|
||||
{
|
||||
// we really should unregister our sleep observer
|
||||
notifySleepObserver.unobserve();
|
||||
notifyDeepSleepObserver.unobserve();
|
||||
notifySleepObserver.unobserve(¬ifySleep);
|
||||
notifyDeepSleepObserver.unobserve(¬ifyDeepSleep);
|
||||
}
|
||||
|
||||
bool GPS::hasLock() { return hasValidLocation; }
|
||||
bool GPS::hasLock()
|
||||
{
|
||||
return hasValidLocation;
|
||||
}
|
||||
|
||||
bool GPS::hasFlow()
|
||||
{
|
||||
return hasGPS;
|
||||
}
|
||||
|
||||
// Allow defining the polarity of the WAKE output. default is active high
|
||||
#ifndef GPS_WAKE_ACTIVE
|
||||
@@ -150,40 +361,27 @@ void GPS::setAwake(bool on)
|
||||
*/
|
||||
uint32_t GPS::getWakeTime() const
|
||||
{
|
||||
uint32_t t = radioConfig.preferences.gps_attempt_time;
|
||||
uint32_t t = config.position.gps_attempt_time;
|
||||
|
||||
if (t == UINT32_MAX)
|
||||
return t; // already maxint
|
||||
|
||||
if (t == 0)
|
||||
t = (radioConfig.preferences.role == Role_Router) ? 5 * 60 : 15 * 60; // Allow up to 15 mins for each attempt (probably will be much
|
||||
// less if we can find sats) or less if a router
|
||||
|
||||
t *= 1000; // msecs
|
||||
|
||||
return t;
|
||||
return t * 1000;
|
||||
}
|
||||
|
||||
/** Get how long we should sleep between aqusition attempts in msecs
|
||||
*/
|
||||
uint32_t GPS::getSleepTime() const
|
||||
{
|
||||
uint32_t t = radioConfig.preferences.gps_update_interval;
|
||||
bool gps_disabled = radioConfig.preferences.gps_disabled;
|
||||
bool loc_share_disabled = radioConfig.preferences.location_share_disabled;
|
||||
uint32_t t = config.position.gps_update_interval;
|
||||
bool gps_enabled = config.position.gps_enabled;
|
||||
|
||||
if (gps_disabled || loc_share_disabled)
|
||||
if (!gps_enabled)
|
||||
t = UINT32_MAX; // Sleep forever now
|
||||
|
||||
if (t == UINT32_MAX)
|
||||
return t; // already maxint
|
||||
|
||||
if (t == 0) // default - unset in preferences
|
||||
t = (radioConfig.preferences.role == Role_Router) ? 24 * 60 * 60 : 2 * 60; // 2 mins or once per day for routers
|
||||
|
||||
t *= 1000;
|
||||
|
||||
return t;
|
||||
|
||||
return t * 1000;
|
||||
}
|
||||
|
||||
void GPS::publishUpdate()
|
||||
@@ -192,12 +390,10 @@ void GPS::publishUpdate()
|
||||
shouldPublish = false;
|
||||
|
||||
// In debug logs, identify position by @timestamp:stage (stage 2 = publish)
|
||||
DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n",
|
||||
p.pos_timestamp, hasValidLocation, hasLock());
|
||||
DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", p.timestamp, hasValidLocation, hasLock());
|
||||
|
||||
// Notify any status instances that are observing us
|
||||
const meshtastic::GPSStatus status =
|
||||
meshtastic::GPSStatus(hasValidLocation, isConnected(), p);
|
||||
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), p);
|
||||
newStatus.notifyObservers(&status);
|
||||
}
|
||||
}
|
||||
@@ -207,6 +403,15 @@ int32_t GPS::runOnce()
|
||||
if (whileIdle()) {
|
||||
// if we have received valid NMEA claim we are connected
|
||||
setConnected();
|
||||
} else {
|
||||
if(gnssModel == GNSS_MODEL_UBLOX){
|
||||
// reset the GPS on next bootup
|
||||
if(devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) {
|
||||
DEBUG_MSG("GPS is not communicating, trying factory reset on next bootup.\n");
|
||||
devicestate.did_gps_reset = false;
|
||||
nodeDB.saveDeviceStateToDisk();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we are overdue for an update, turn on the GPS and at least publish the current status
|
||||
@@ -306,45 +511,131 @@ int GPS::prepareDeepSleep(void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef GPS_TX_PIN
|
||||
#include "UBloxGPS.h"
|
||||
#endif
|
||||
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 ;
|
||||
|
||||
#ifndef NO_GPS
|
||||
memset(&info, 0, sizeof(struct uBloxGnssModelInfo));
|
||||
|
||||
// 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");
|
||||
delay(20);
|
||||
|
||||
// Get version information
|
||||
_serial_gps->write("$PCAS06,0*1B\r\n");
|
||||
uint32_t startTimeout = millis() + 500;
|
||||
while (millis() < startTimeout) {
|
||||
if (_serial_gps->available()) {
|
||||
String ver = _serial_gps->readStringUntil('\r');
|
||||
// Get module info , If the correct header is returned,
|
||||
// it can be determined that it is the MTK chip
|
||||
int index = ver.indexOf("$");
|
||||
if(index != -1){
|
||||
ver = ver.substring(index);
|
||||
if (ver.startsWith("$GPTXT,01,01,02")) {
|
||||
DEBUG_MSG("L76K GNSS init succeeded, using L76K GNSS Module\n");
|
||||
return GNSS_MODEL_MTK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
|
||||
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
|
||||
// Check that the returned response class and message ID are correct
|
||||
if (!getAck(buffer, 256, 0x06, 0x08)) {
|
||||
DEBUG_MSG("Warning: Failed to find UBlox & MTK GNSS Module\n");
|
||||
return GNSS_MODEL_UNKONW;
|
||||
}
|
||||
|
||||
// Get Ublox gnss module hardware and software info
|
||||
uint8_t cfg_get_hw[] = {0xB5, 0x62, 0x0A, 0x04, 0x00, 0x00, 0x0E, 0x34};
|
||||
_serial_gps->write(cfg_get_hw, sizeof(cfg_get_hw));
|
||||
|
||||
uint16_t len = getAck(buffer, 256, 0x0A, 0x04);
|
||||
if (len) {
|
||||
|
||||
uint16_t position = 0;
|
||||
for (int i = 0; i < 30; i++) {
|
||||
info.swVersion[i] = buffer[position];
|
||||
position++;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
info.hwVersion[i] = buffer[position];
|
||||
position++;
|
||||
}
|
||||
|
||||
while (len >= position + 30) {
|
||||
for (int i = 0; i < 30; i++) {
|
||||
info.extension[info.extensionNo][i] = buffer[position];
|
||||
position++;
|
||||
}
|
||||
info.extensionNo++;
|
||||
if (info.extensionNo > 9)
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_MSG("Module Info : \n");
|
||||
DEBUG_MSG("Soft version: %s\n",info.swVersion);
|
||||
DEBUG_MSG("Hard version: %s\n",info.hwVersion);
|
||||
DEBUG_MSG("Extensions:%d\n",info.extensionNo);
|
||||
for (int i = 0; i < info.extensionNo; i++) {
|
||||
DEBUG_MSG(" %s\n",info.extension[i]);
|
||||
}
|
||||
|
||||
memset(buffer,0,sizeof(buffer));
|
||||
|
||||
//tips: extensionNo field is 0 on some 6M GNSS modules
|
||||
for (int i = 0; i < info.extensionNo; ++i) {
|
||||
if (!strncmp(info.extension[i], "OD=", 3)) {
|
||||
strcpy((char *)buffer, &(info.extension[i][3]));
|
||||
DEBUG_MSG("GetModel:%s\n",(char *)buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen((char*)buffer)) {
|
||||
DEBUG_MSG("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n" , buffer);
|
||||
}else{
|
||||
DEBUG_MSG("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
|
||||
}
|
||||
|
||||
return GNSS_MODEL_UBLOX;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAS_GPS
|
||||
#include "NMEAGPS.h"
|
||||
#endif
|
||||
|
||||
GPS *createGps()
|
||||
{
|
||||
|
||||
#ifdef NO_GPS
|
||||
#if !HAS_GPS
|
||||
return nullptr;
|
||||
#else
|
||||
if (!radioConfig.preferences.gps_disabled){
|
||||
if (config.position.gps_enabled) {
|
||||
#ifdef GPS_ALTITUDE_HAE
|
||||
DEBUG_MSG("Using HAE altitude model\n");
|
||||
#else
|
||||
DEBUG_MSG("Using MSL altitude model\n");
|
||||
#endif
|
||||
// If we don't have bidirectional comms, we can't even try talking to UBLOX
|
||||
#ifdef GPS_TX_PIN
|
||||
// Init GPS - first try ublox
|
||||
UBloxGPS *ublox = new UBloxGPS();
|
||||
|
||||
if (!ublox->setup()) {
|
||||
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
|
||||
delete ublox;
|
||||
ublox = NULL;
|
||||
} else {
|
||||
DEBUG_MSG("Using UBLOX Mode\n");
|
||||
return ublox;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (GPS::_serial_gps) {
|
||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||
// assume NMEA at 9600 baud.
|
||||
DEBUG_MSG("Using NMEA Mode\n");
|
||||
GPS *new_gps = new NMEAGPS();
|
||||
new_gps->setup();
|
||||
return new_gps;
|
||||
|
||||
@@ -4,6 +4,20 @@
|
||||
#include "Observer.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
|
||||
struct uBloxGnssModelInfo {
|
||||
char swVersion[30];
|
||||
char hwVersion[10];
|
||||
uint8_t extensionNo;
|
||||
char extension[10][30];
|
||||
} ;
|
||||
|
||||
typedef enum{
|
||||
GNSS_MODEL_MTK,
|
||||
GNSS_MODEL_UBLOX,
|
||||
GNSS_MODEL_UNKONW,
|
||||
}GnssModel_t;
|
||||
|
||||
// Generate a string representation of DOP
|
||||
const char *getDOPString(uint32_t dop);
|
||||
|
||||
@@ -40,9 +54,6 @@ class GPS : private concurrency::OSThread
|
||||
/** If !NULL we will use this serial port to construct our GPS */
|
||||
static HardwareSerial *_serial_gps;
|
||||
|
||||
/** If !0 we will attempt to connect to the GPS over I2C */
|
||||
static uint8_t i2cAddress;
|
||||
|
||||
Position p = Position_init_default;
|
||||
|
||||
GPS() : concurrency::OSThread("GPS") {}
|
||||
@@ -60,6 +71,9 @@ class GPS : private concurrency::OSThread
|
||||
/// Returns true if we have acquired GPS lock.
|
||||
virtual bool hasLock();
|
||||
|
||||
/// Returns true if there's valid data flow with the chip.
|
||||
virtual bool hasFlow();
|
||||
|
||||
/// Return true if we are connected to a GPS
|
||||
bool isConnected() const { return hasGPS; }
|
||||
|
||||
@@ -138,12 +152,22 @@ class GPS : private concurrency::OSThread
|
||||
*/
|
||||
uint32_t getSleepTime() const;
|
||||
|
||||
bool getACK(uint8_t c, uint8_t i);
|
||||
|
||||
/**
|
||||
* Tell users we have new GPS readings
|
||||
*/
|
||||
void publishUpdate();
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
// Get GNSS model
|
||||
GnssModel_t probe();
|
||||
|
||||
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
|
||||
|
||||
protected:
|
||||
GnssModel_t gnssModel = GNSS_MODEL_UNKONW;
|
||||
};
|
||||
|
||||
// Creates an instance of the GPS class.
|
||||
|
||||
@@ -379,7 +379,7 @@ float GeoCoord::latLongToMeter(double lat_a, double lng_a, double lat_b, double
|
||||
* Latitude of the second point
|
||||
* @param lon2
|
||||
* Longitude of the second point
|
||||
* @return Bearing between the two points in radians. A value of 0 means due
|
||||
* @return Bearing from point 1 to point 2 in radians. A value of 0 means due
|
||||
* north.
|
||||
*/
|
||||
float GeoCoord::bearing(double lat1, double lon1, double lat2, double lon2)
|
||||
|
||||
@@ -17,6 +17,26 @@ static int32_t toDegInt(RawDegrees d)
|
||||
return r;
|
||||
}
|
||||
|
||||
bool NMEAGPS::factoryReset()
|
||||
{
|
||||
#ifdef PIN_GPS_REINIT
|
||||
//The L76K GNSS on the T-Echo requires the RESET pin to be pulled LOW
|
||||
digitalWrite(PIN_GPS_REINIT, 0);
|
||||
pinMode(PIN_GPS_REINIT, OUTPUT);
|
||||
delay(150); //The L76K datasheet calls for at least 100MS delay
|
||||
digitalWrite(PIN_GPS_REINIT, 1);
|
||||
#endif
|
||||
|
||||
// send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX.
|
||||
// Factory Reset
|
||||
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF,
|
||||
0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
|
||||
_serial_gps->write(_message_reset,sizeof(_message_reset));
|
||||
delay(1000);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NMEAGPS::setupGPS()
|
||||
{
|
||||
GPS::setupGPS();
|
||||
@@ -64,11 +84,12 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
t.tm_mon = d.month() - 1;
|
||||
t.tm_year = d.year() - 1900;
|
||||
t.tm_isdst = false;
|
||||
DEBUG_MSG("NMEA GPS time %d-%d-%d %d:%d:%d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
|
||||
|
||||
perhapsSetRTC(RTCQualityGPS, t);
|
||||
|
||||
return true;
|
||||
if (t.tm_mon > -1){
|
||||
DEBUG_MSG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
|
||||
perhapsSetRTC(RTCQualityGPS, t);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
@@ -128,12 +149,20 @@ bool NMEAGPS::lookForLocation()
|
||||
auto loc = reader.location.value();
|
||||
|
||||
// Bail out EARLY to avoid overwriting previous good data (like #857)
|
||||
if(toDegInt(loc.lat) == 0) {
|
||||
DEBUG_MSG("Ignoring bogus NMEA position\n");
|
||||
if (toDegInt(loc.lat) > 900000000) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("Bail out EARLY on LAT %i\n",toDegInt(loc.lat));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
if (toDegInt(loc.lng) > 1800000000) {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("Bail out EARLY on LNG %i\n",toDegInt(loc.lng));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
|
||||
p.location_source = Position_LocSource_LOC_INTERNAL;
|
||||
|
||||
// Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
|
||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
@@ -154,8 +183,8 @@ bool NMEAGPS::lookForLocation()
|
||||
p.latitude_i = toDegInt(loc.lat);
|
||||
p.longitude_i = toDegInt(loc.lng);
|
||||
|
||||
p.alt_geoid_sep = reader.geoidHeight.meters();
|
||||
p.altitude_hae = reader.altitude.meters() + p.alt_geoid_sep;
|
||||
p.altitude_geoidal_separation = reader.geoidHeight.meters();
|
||||
p.altitude_hae = reader.altitude.meters() + p.altitude_geoidal_separation;
|
||||
p.altitude = reader.altitude.meters();
|
||||
|
||||
p.fix_quality = fixQual;
|
||||
@@ -172,7 +201,7 @@ bool NMEAGPS::lookForLocation()
|
||||
t.tm_mon = reader.date.month() - 1;
|
||||
t.tm_year = reader.date.year() - 1900;
|
||||
t.tm_isdst = false;
|
||||
p.pos_timestamp = mktime(&t);
|
||||
p.timestamp = mktime(&t);
|
||||
|
||||
// Nice to have, if available
|
||||
if (reader.satellites.isUpdated()) {
|
||||
@@ -188,13 +217,10 @@ bool NMEAGPS::lookForLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// REDUNDANT?
|
||||
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
|
||||
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, dop=%g, heading=%f\n",
|
||||
latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2,
|
||||
heading * 1e-5);
|
||||
*/
|
||||
if (reader.speed.isUpdated() && reader.speed.isValid()) {
|
||||
p.ground_speed = reader.speed.kmph();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -213,6 +239,10 @@ bool NMEAGPS::hasLock()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NMEAGPS::hasFlow()
|
||||
{
|
||||
return reader.passedChecksum() > 0;
|
||||
}
|
||||
|
||||
bool NMEAGPS::whileIdle()
|
||||
{
|
||||
|
||||
@@ -25,6 +25,8 @@ class NMEAGPS : public GPS
|
||||
public:
|
||||
virtual bool setupGPS() override;
|
||||
|
||||
virtual bool factoryReset() override;
|
||||
|
||||
protected:
|
||||
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
|
||||
*
|
||||
@@ -49,4 +51,6 @@ class NMEAGPS : public GPS
|
||||
virtual bool lookForLocation() override;
|
||||
|
||||
virtual bool hasLock() override;
|
||||
|
||||
virtual bool hasFlow() override;
|
||||
};
|
||||
|
||||
76
src/gps/NMEAWPL.cpp
Normal file
76
src/gps/NMEAWPL.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "NMEAWPL.h"
|
||||
|
||||
/* -------------------------------------------
|
||||
* 1 2 3 4 5 6
|
||||
* | | | | | |
|
||||
* $--WPL,llll.ll,a,yyyyy.yy,a,c--c*hh<CR><LF>
|
||||
*
|
||||
* Field Number:
|
||||
* 1 Latitude
|
||||
* 2 N or S (North or South)
|
||||
* 3 Longitude
|
||||
* 4 E or W (East or West)
|
||||
* 5 Waypoint name
|
||||
* 6 Checksum
|
||||
* -------------------------------------------
|
||||
*/
|
||||
|
||||
uint32_t printWPL(char *buf, const Position &pos, const char *name)
|
||||
{
|
||||
uint32_t len = sprintf(buf, "$GNWPL,%07.2f,%c,%08.2f,%c,%s", pos.latitude_i * 1e-5, pos.latitude_i < 0 ? 'S' : 'N', pos.longitude_i * 1e-5, pos.longitude_i < 0 ? 'W' : 'E', name);
|
||||
uint32_t chk = 0;
|
||||
for (uint32_t i = 1; i < len; i++) {
|
||||
chk ^= buf[i];
|
||||
}
|
||||
len += sprintf(buf + len, "*%02X\r\n", chk);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* -------------------------------------------
|
||||
* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
* | | | | | | | | | | | | | | |
|
||||
* $--GGA,hhmmss.ss,ddmm.mm,a,ddmm.mm,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh<CR><LF>
|
||||
*
|
||||
* Field Number:
|
||||
* 1 UTC of this position report, hh is hours, mm is minutes, ss.ss is seconds.
|
||||
* 2 Latitude
|
||||
* 3 N or S (North or South)
|
||||
* 4 Longitude
|
||||
* 5 E or W (East or West)
|
||||
* 6 GPS Quality Indicator (non null)
|
||||
* 7 Number of satellites in use, 00 - 12
|
||||
* 8 Horizontal Dilution of precision (meters)
|
||||
* 9 Antenna Altitude above/below mean-sea-level (geoid) (in meters)
|
||||
* 10 Units of antenna altitude, meters
|
||||
* 11 Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level below ellipsoid
|
||||
* 12 Units of geoidal separation, meters
|
||||
* 13 Age of differential GPS data, time in seconds since last SC104 type 1 or 9 update, null field when DGPS is not used
|
||||
* 14 Differential reference station ID, 0000-1023
|
||||
* 15 Checksum
|
||||
* -------------------------------------------
|
||||
*/
|
||||
|
||||
uint32_t printGGA(char *buf, const Position &pos)
|
||||
{
|
||||
uint32_t len = sprintf(buf, "$GNGGA,%06u.%03u,%07.2f,%c,%08.2f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d",
|
||||
pos.time / 1000,
|
||||
pos.time % 1000,
|
||||
pos.latitude_i * 1e-5, pos.latitude_i < 0 ? 'S' : 'N',
|
||||
pos.longitude_i * 1e-5, pos.longitude_i < 0 ? 'W' : 'E',
|
||||
pos.fix_type,
|
||||
pos.sats_in_view,
|
||||
pos.HDOP,
|
||||
pos.altitude,
|
||||
'M',
|
||||
pos.altitude_geoidal_separation,
|
||||
'M',
|
||||
0,
|
||||
0);
|
||||
|
||||
uint32_t chk = 0;
|
||||
for (uint32_t i = 1; i < len; i++) {
|
||||
chk ^= buf[i];
|
||||
}
|
||||
len += sprintf(buf + len, "*%02X\r\n", chk);
|
||||
return len;
|
||||
}
|
||||
7
src/gps/NMEAWPL.h
Normal file
7
src/gps/NMEAWPL.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "main.h"
|
||||
|
||||
uint32_t printWPL(char *buf, const Position &pos, const char *name);
|
||||
uint32_t printGGA(char *buf, const Position &pos);
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
@@ -18,14 +19,57 @@ static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only upda
|
||||
void readFromRTC()
|
||||
{
|
||||
struct timeval tv; /* btw settimeofday() is helpfull here too*/
|
||||
|
||||
#ifdef RV3028_RTC
|
||||
if(rtc_found == RV3028_RTC) {
|
||||
uint32_t now = millis();
|
||||
Melopero_RV3028 rtc;
|
||||
rtc.initI2C();
|
||||
tm t;
|
||||
t.tm_year = rtc.getYear() - 1900;
|
||||
t.tm_mon = rtc.getMonth() - 1;
|
||||
t.tm_mday = rtc.getDate();
|
||||
t.tm_hour = rtc.getHour();
|
||||
t.tm_min = rtc.getMinute();
|
||||
t.tm_sec = rtc.getSecond();
|
||||
tv.tv_sec = mktime(&t);
|
||||
tv.tv_usec = 0;
|
||||
DEBUG_MSG("Read RTC time from RV3028 as %ld\n", tv.tv_sec);
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
if (currentQuality == RTCQualityNone) {
|
||||
currentQuality = RTCQualityDevice;
|
||||
}
|
||||
}
|
||||
#elif defined(PCF8563_RTC)
|
||||
if(rtc_found == PCF8563_RTC) {
|
||||
uint32_t now = millis();
|
||||
PCF8563_Class rtc;
|
||||
rtc.begin();
|
||||
auto tc = rtc.getDateTime();
|
||||
tm t;
|
||||
t.tm_year = tc.year - 1900;
|
||||
t.tm_mon = tc.month - 1;
|
||||
t.tm_mday = tc.day;
|
||||
t.tm_hour = tc.hour;
|
||||
t.tm_min = tc.minute;
|
||||
t.tm_sec = tc.second;
|
||||
tv.tv_sec = mktime(&t);
|
||||
tv.tv_usec = 0;
|
||||
DEBUG_MSG("Read RTC time from PCF8563 as %ld\n", tv.tv_sec);
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
if (currentQuality == RTCQualityNone) {
|
||||
currentQuality = RTCQualityDevice;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!gettimeofday(&tv, NULL)) {
|
||||
uint32_t now = millis();
|
||||
|
||||
DEBUG_MSG("Read RTC time as %ld (cur millis %u) quality=%d\n", tv.tv_sec, now, currentQuality);
|
||||
DEBUG_MSG("Read RTC time as %ld\n", tv.tv_sec);
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||
@@ -55,12 +99,28 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
zeroOffsetSecs = tv->tv_sec;
|
||||
|
||||
// If this platform has a setable RTC, set it
|
||||
#ifndef NO_ESP32
|
||||
#ifdef RV3028_RTC
|
||||
if(rtc_found == RV3028_RTC) {
|
||||
Melopero_RV3028 rtc;
|
||||
rtc.initI2C();
|
||||
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);
|
||||
DEBUG_MSG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
|
||||
}
|
||||
#elif defined(PCF8563_RTC)
|
||||
if(rtc_found == PCF8563_RTC) {
|
||||
PCF8563_Class rtc;
|
||||
rtc.begin();
|
||||
tm *t = localtime(&tv->tv_sec);
|
||||
rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
|
||||
DEBUG_MSG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
|
||||
}
|
||||
#elif defined(ARCH_ESP32)
|
||||
settimeofday(tv, NULL);
|
||||
#endif
|
||||
|
||||
// nrf52 doesn't have a readable RTC (yet - software not written)
|
||||
#if defined(PORTDUINO) || !defined(NO_ESP32)
|
||||
#ifdef HAS_RTC
|
||||
readFromRTC();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -5,17 +5,21 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
enum RTCQuality {
|
||||
|
||||
/// We haven't had our RTC set yet
|
||||
RTCQualityNone = 0,
|
||||
|
||||
/// We got time from an onboard peripheral after boot.
|
||||
RTCQualityDevice = 1,
|
||||
|
||||
/// Some other node gave us a time we can use
|
||||
RTCQualityFromNet = 1,
|
||||
RTCQualityFromNet = 2,
|
||||
|
||||
/// Our time is based on NTP
|
||||
RTCQualityNTP= 2,
|
||||
RTCQualityNTP = 3,
|
||||
|
||||
/// Our time is based on our own GPS
|
||||
RTCQualityGPS = 3
|
||||
RTCQualityGPS = 4
|
||||
};
|
||||
|
||||
RTCQuality getRTCQuality();
|
||||
|
||||
@@ -1,328 +0,0 @@
|
||||
#include "configuration.h"
|
||||
#include "UBloxGPS.h"
|
||||
#include "RTC.h"
|
||||
#include "error.h"
|
||||
#include "sleep.h"
|
||||
#include <assert.h>
|
||||
|
||||
// if gps_update_interval below this value, do not powercycle the GPS
|
||||
#define UBLOX_POWEROFF_THRESHOLD 90
|
||||
|
||||
#define PDOP_INVALID 9999
|
||||
|
||||
// #define UBX_MODE_NMEA
|
||||
|
||||
extern RadioConfig radioConfig;
|
||||
|
||||
UBloxGPS::UBloxGPS() {}
|
||||
|
||||
bool UBloxGPS::tryConnect()
|
||||
{
|
||||
bool c = false;
|
||||
|
||||
if (_serial_gps)
|
||||
c = ublox.begin(*_serial_gps);
|
||||
|
||||
if (!c && i2cAddress) {
|
||||
extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which
|
||||
// supports the newer API
|
||||
neo6M = true;
|
||||
|
||||
c = ublox.begin(Wire, i2cAddress);
|
||||
}
|
||||
|
||||
if (c)
|
||||
setConnected();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
bool UBloxGPS::setupGPS()
|
||||
{
|
||||
GPS::setupGPS();
|
||||
|
||||
// uncomment to see debug info
|
||||
// ublox.enableDebugging(Serial);
|
||||
|
||||
// try a second time, the ublox lib serial parsing is buggy?
|
||||
// see https://github.com/meshtastic/Meshtastic-device/issues/376
|
||||
for (int i = 0; (i < 3) && !tryConnect(); i++)
|
||||
delay(500);
|
||||
|
||||
if (isConnected()) {
|
||||
#ifdef UBX_MODE_NMEA
|
||||
DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n");
|
||||
DEBUG_MSG("- GPS errors below are related and safe to ignore\n");
|
||||
#else
|
||||
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
||||
#endif
|
||||
|
||||
if (!setUBXMode())
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
||||
|
||||
#ifdef UBX_MODE_NMEA
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool UBloxGPS::setUBXMode()
|
||||
{
|
||||
#ifdef UBX_MODE_NMEA
|
||||
if (_serial_gps) {
|
||||
ublox.setUART1Output(COM_TYPE_NMEA, 1000);
|
||||
}
|
||||
if (i2cAddress) {
|
||||
ublox.setI2COutput(COM_TYPE_NMEA, 1000);
|
||||
}
|
||||
|
||||
return false; // pretend initialization failed to force NMEA mode
|
||||
#endif
|
||||
|
||||
if (_serial_gps) {
|
||||
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
|
||||
return false;
|
||||
}
|
||||
if (i2cAddress) {
|
||||
if (!ublox.setI2COutput(COM_TYPE_UBX, 1000))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ublox.setNavigationFrequency(1, 1000)) // Produce 4x/sec to keep the amount of time we stall in getPVT low
|
||||
return false;
|
||||
|
||||
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
|
||||
// assert(ok);
|
||||
// ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
|
||||
// assert(ok);
|
||||
|
||||
// per https://github.com/meshtastic/Meshtastic-device/issues/376 powerSaveMode might not work with the marginal
|
||||
// TTGO antennas
|
||||
// if (!ublox.powerSaveMode(true, 2000)) // use power save mode, the default timeout (1100ms seems a bit too tight)
|
||||
// return false;
|
||||
|
||||
if (!ublox.saveConfiguration(3000))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset our GPS back to factory settings
|
||||
*
|
||||
* @return true for success
|
||||
*/
|
||||
bool UBloxGPS::factoryReset()
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// It is useful to force back into factory defaults (9600baud, NMEA to test the behavior of boards that don't have
|
||||
// GPS_TX connected)
|
||||
ublox.factoryReset();
|
||||
delay(5000);
|
||||
tryConnect(); // sets isConnected
|
||||
|
||||
// try a second time, the ublox lib serial parsing is buggy?
|
||||
for (int i = 0; (i < 3) && !tryConnect(); i++)
|
||||
delay(500);
|
||||
|
||||
DEBUG_MSG("GPS Factory reset success=%d\n", isConnected());
|
||||
if (isConnected())
|
||||
ok = setUBXMode();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/** Idle processing while GPS is looking for lock */
|
||||
void UBloxGPS::whileActive()
|
||||
{
|
||||
ublox.flushPVT(); // reset ALL freshness flags first
|
||||
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
|
||||
|
||||
// Ask for a new position fix - hopefully it will have results ready by next time
|
||||
// the order here is important, because we only check for has latitude when reading
|
||||
|
||||
//ublox.getSIV(maxWait()); // redundant with getPDOP below
|
||||
ublox.getPDOP(maxWait()); // will trigger getSOL on NEO6, getP on others
|
||||
ublox.getP(maxWait()); // will trigger getPosLLH on NEO6, getP on others
|
||||
|
||||
// the fixType flag will be checked and updated in lookForLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
bool UBloxGPS::lookForTime()
|
||||
{
|
||||
if (ublox.moduleQueried.gpsSecond) {
|
||||
/* Convert to unix time
|
||||
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January
|
||||
1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
|
||||
*/
|
||||
struct tm t;
|
||||
t.tm_sec = ublox.getSecond(0);
|
||||
t.tm_min = ublox.getMinute(0);
|
||||
t.tm_hour = ublox.getHour(0);
|
||||
t.tm_mday = ublox.getDay(0);
|
||||
t.tm_mon = ublox.getMonth(0) - 1;
|
||||
t.tm_year = ublox.getYear(0) - 1900;
|
||||
t.tm_isdst = false;
|
||||
perhapsSetRTC(RTCQualityGPS, t);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
bool UBloxGPS::lookForLocation()
|
||||
{
|
||||
bool foundLocation = false;
|
||||
|
||||
// check if a complete GPS solution set is available for reading
|
||||
// (some of these, like lat/lon are redundant and can be removed)
|
||||
if ( ! (ublox.moduleQueried.fixType &&
|
||||
ublox.moduleQueried.latitude &&
|
||||
ublox.moduleQueried.longitude &&
|
||||
ublox.moduleQueried.altitude &&
|
||||
ublox.moduleQueried.pDOP &&
|
||||
ublox.moduleQueried.SIV &&
|
||||
ublox.moduleQueried.gpsDay))
|
||||
{
|
||||
// Not ready? No problem! We'll try again later.
|
||||
return false;
|
||||
}
|
||||
|
||||
fixType = ublox.getFixType();
|
||||
#ifdef UBLOX_EXTRAVERBOSE
|
||||
DEBUG_MSG("FixType=%d\n", fixType);
|
||||
#endif
|
||||
|
||||
|
||||
// check if GPS has an acceptable lock
|
||||
if (! hasLock()) {
|
||||
ublox.flushPVT(); // reset ALL freshness flags
|
||||
return false;
|
||||
}
|
||||
|
||||
// read lat/lon/alt/dop data into temporary variables to avoid
|
||||
// overwriting global variables with potentially invalid data
|
||||
int32_t tmp_dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
|
||||
int32_t tmp_lat = ublox.getLatitude(0);
|
||||
int32_t tmp_lon = ublox.getLongitude(0);
|
||||
int32_t tmp_alt_msl = ublox.getAltitudeMSL(0);
|
||||
int32_t tmp_alt_hae = ublox.getAltitude(0);
|
||||
int32_t max_dop = PDOP_INVALID;
|
||||
if (radioConfig.preferences.gps_max_dop)
|
||||
max_dop = radioConfig.preferences.gps_max_dop * 100; // scaling
|
||||
|
||||
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
|
||||
// don't read it here - it will generate an ignored getPVT command on the 6ms
|
||||
// heading = ublox.getHeading(0);
|
||||
|
||||
// read positional timestamp
|
||||
struct tm t;
|
||||
t.tm_sec = ublox.getSecond(0);
|
||||
t.tm_min = ublox.getMinute(0);
|
||||
t.tm_hour = ublox.getHour(0);
|
||||
t.tm_mday = ublox.getDay(0);
|
||||
t.tm_mon = ublox.getMonth(0) - 1;
|
||||
t.tm_year = ublox.getYear(0) - 1900;
|
||||
t.tm_isdst = false;
|
||||
|
||||
time_t tmp_ts = mktime(&t);
|
||||
|
||||
// FIXME - can opportunistically attempt to set RTC from GPS timestamp?
|
||||
|
||||
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
||||
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
||||
// FIXME - NULL ISLAND is a real location on Earth!
|
||||
foundLocation = (tmp_lat != 0) && (tmp_lon != 0) &&
|
||||
(tmp_lat <= 900000000) && (tmp_lat >= -900000000) &&
|
||||
(tmp_dop < max_dop);
|
||||
|
||||
// only if entire dataset is valid, update globals from temp vars
|
||||
if (foundLocation) {
|
||||
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
|
||||
p.longitude_i = tmp_lon;
|
||||
p.latitude_i = tmp_lat;
|
||||
if (fixType > 2) {
|
||||
// if fix is 2d, ignore altitude data
|
||||
p.altitude = tmp_alt_msl / 1000;
|
||||
p.altitude_hae = tmp_alt_hae / 1000;
|
||||
p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000;
|
||||
} else {
|
||||
#ifdef GPS_EXTRAVERBOSE
|
||||
DEBUG_MSG("no altitude data (fixType=%d)\n", fixType);
|
||||
#endif
|
||||
// clean up old values in case it's a 3d-2d fix transition
|
||||
p.altitude = p.altitude_hae = p.alt_geoid_sep = 0;
|
||||
}
|
||||
p.pos_timestamp = tmp_ts;
|
||||
p.PDOP = tmp_dop;
|
||||
p.fix_type = fixType;
|
||||
p.sats_in_view = ublox.getSIV(0);
|
||||
// In debug logs, identify position by @timestamp:stage (stage 1 = birth)
|
||||
DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts);
|
||||
} else {
|
||||
// INVALID solution - should never happen
|
||||
DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n",
|
||||
tmp_lat, tmp_lon, tmp_alt_hae, tmp_dop);
|
||||
}
|
||||
|
||||
ublox.flushPVT(); // reset ALL freshness flags at the end
|
||||
|
||||
return foundLocation;
|
||||
}
|
||||
|
||||
bool UBloxGPS::hasLock()
|
||||
{
|
||||
if (radioConfig.preferences.gps_accept_2d)
|
||||
return (fixType >= 2 && fixType <= 4);
|
||||
else
|
||||
return (fixType >= 3 && fixType <= 4);
|
||||
}
|
||||
|
||||
bool UBloxGPS::whileIdle()
|
||||
{
|
||||
// if using i2c or serial look too see if any chars are ready
|
||||
return ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
|
||||
}
|
||||
|
||||
/// If possible force the GPS into sleep/low power mode
|
||||
/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up
|
||||
void UBloxGPS::sleep()
|
||||
{
|
||||
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
|
||||
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
|
||||
ublox.powerOff();
|
||||
// setGPSPower(false);
|
||||
}
|
||||
}
|
||||
|
||||
void UBloxGPS::wake()
|
||||
{
|
||||
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
|
||||
fixType = 0; // assume we have no fix yet
|
||||
}
|
||||
|
||||
// this is idempotent
|
||||
setGPSPower(true);
|
||||
|
||||
// Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff()
|
||||
// Give time for the GPS to boot
|
||||
// delay(200);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "GPS.h"
|
||||
#include "Observer.h"
|
||||
#include "SparkFun_Ublox_Arduino_Library.h"
|
||||
|
||||
/**
|
||||
* A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading)
|
||||
*
|
||||
* When new data is available it will notify observers.
|
||||
*/
|
||||
class UBloxGPS : public GPS
|
||||
{
|
||||
SFE_UBLOX_GPS ublox;
|
||||
uint8_t fixType = 0;
|
||||
|
||||
public:
|
||||
UBloxGPS();
|
||||
|
||||
/**
|
||||
* Reset our GPS back to factory settings
|
||||
*
|
||||
* @return true for success
|
||||
*/
|
||||
bool factoryReset() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns true if we succeeded
|
||||
*/
|
||||
virtual bool setupGPS() override;
|
||||
|
||||
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
|
||||
*
|
||||
* Return true if we received a valid message from the GPS
|
||||
*/
|
||||
virtual bool whileIdle() override;
|
||||
|
||||
/** Idle processing while GPS is looking for lock */
|
||||
virtual void whileActive() override;
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a time
|
||||
*/
|
||||
virtual bool lookForTime() override;
|
||||
|
||||
/**
|
||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||
* Override this method to check for new locations
|
||||
*
|
||||
* @return true if we've acquired a new location
|
||||
*/
|
||||
virtual bool lookForLocation() override;
|
||||
virtual bool hasLock() override;
|
||||
|
||||
/// If possible force the GPS into sleep/low power mode
|
||||
virtual void sleep() override;
|
||||
virtual void wake() override;
|
||||
|
||||
private:
|
||||
/// Attempt to connect to our GPS, returns false if no gps is present
|
||||
bool tryConnect();
|
||||
|
||||
/// Switch to our desired operating mode and save the settings to flash
|
||||
/// returns true for success
|
||||
bool setUBXMode();
|
||||
|
||||
uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ }
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef HAS_EINK
|
||||
#ifdef USE_EINK
|
||||
#include "main.h"
|
||||
#include "EInkDisplay2.h"
|
||||
#include "SPILock.h"
|
||||
#include <SPI.h>
|
||||
@@ -13,8 +14,8 @@
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_154_D67
|
||||
#elif defined(RAK4630)
|
||||
|
||||
//GxEPD2_213_B74 - RAK14000 2.13 inch b/w 250x128
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_213_B74
|
||||
//GxEPD2_213_BN - RAK14000 2.13 inch b/w 250x122 - changed from GxEPD2_213_B74 - which was not going to give partial update support
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
|
||||
|
||||
//4.2 inch 300x400 - GxEPD2_420_M01
|
||||
//#define TECHO_DISPLAY_MODEL GxEPD2_420_M01
|
||||
@@ -25,6 +26,16 @@
|
||||
//1.54 inch 200x200 - GxEPD2_154_M09
|
||||
//#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
||||
|
||||
#elif defined(PCA10059)
|
||||
|
||||
//4.2 inch 300x400 - GxEPD2_420_M01
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_420_M01
|
||||
|
||||
#elif defined(M5_COREINK)
|
||||
//M5Stack CoreInk
|
||||
//1.54 inch 200x200 - GxEPD2_154_M09
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
||||
|
||||
#endif
|
||||
|
||||
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
|
||||
@@ -35,9 +46,9 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
|
||||
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
|
||||
#elif defined(RAK4630)
|
||||
|
||||
//GxEPD2_213_B74 - RAK14000 2.13 inch b/w 250x128
|
||||
//GxEPD2_213_BN - RAK14000 2.13 inch b/w 250x122
|
||||
setGeometry(GEOMETRY_RAWMODE, 250, 122);
|
||||
|
||||
|
||||
//GxEPD2_420_M01
|
||||
//setGeometry(GEOMETRY_RAWMODE, 300, 400);
|
||||
|
||||
@@ -47,6 +58,17 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
|
||||
//GxEPD2_154_M09
|
||||
//setGeometry(GEOMETRY_RAWMODE, 200, 200);
|
||||
|
||||
#elif defined(PCA10059)
|
||||
|
||||
//GxEPD2_420_M01
|
||||
setGeometry(GEOMETRY_RAWMODE, 300, 400);
|
||||
|
||||
#elif defined(M5_COREINK)
|
||||
|
||||
//M5Stack_CoreInk 200x200
|
||||
//1.54 inch 200x200 - GxEPD2_154_M09
|
||||
setGeometry(GEOMETRY_RAWMODE, EPD_HEIGHT, EPD_WIDTH);
|
||||
|
||||
#endif
|
||||
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
||||
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
|
||||
@@ -71,8 +93,8 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
|
||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
|
||||
for (uint64_t y = 0; y < displayHeight; y++) {
|
||||
for (uint64_t x = 0; x < displayWidth; x++) {
|
||||
for (uint32_t y = 0; y < displayHeight; y++) {
|
||||
for (uint32_t x = 0; x < displayWidth; x++) {
|
||||
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||
auto b = buffer[x + (y / 8) * displayWidth];
|
||||
@@ -81,26 +103,27 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
DEBUG_MSG("Updating T-ECHO E-Paper... ");
|
||||
#elif defined(RAK4630)
|
||||
DEBUG_MSG("Updating RAK4361_5005 E-Paper... ");
|
||||
#endif
|
||||
DEBUG_MSG("Updating E-Paper... ");
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
// ePaper.Reset(); // wake the screen from sleep
|
||||
adafruitDisplay->display(false); // FIXME, use partial update mode
|
||||
#elif defined(RAK4630)
|
||||
|
||||
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
|
||||
adafruitDisplay->display(false); // FIXME, use partial update mode
|
||||
//RAK14000 2.13 inch b/w 250x122 actually now does support partial updates
|
||||
|
||||
//Full update mode (slow)
|
||||
//adafruitDisplay->display(false); // FIXME, use partial update mode
|
||||
|
||||
//Only enable for e-Paper with support for partial updates and comment out above adafruitDisplay->display(false);
|
||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||
// 2.13 inch 250x122 - GxEPD2_213_BN
|
||||
// 2.9 inch 296x128 - GxEPD2_290_T5D
|
||||
// 4.2 inch 300x400 - GxEPD2_420_M01
|
||||
//adafruitDisplay->nextPage();
|
||||
adafruitDisplay->nextPage();
|
||||
|
||||
#elif defined(PCA10059) || defined(M5_COREINK)
|
||||
adafruitDisplay->nextPage();
|
||||
#endif
|
||||
|
||||
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
|
||||
@@ -163,19 +186,36 @@ bool EInkDisplay::connect()
|
||||
}
|
||||
#elif defined(RAK4630)
|
||||
{
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
if (eink_found) {
|
||||
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, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
|
||||
adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
//RAK14000 2.13 inch b/w 250x122 does not support partial updates
|
||||
adafruitDisplay->setRotation(3);
|
||||
//For 1.54, 2.9 and 4.2
|
||||
//adafruitDisplay->setRotation(1);
|
||||
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
//RAK14000 2.13 inch b/w 250x122 does actually now support partial updates
|
||||
adafruitDisplay->setRotation(3);
|
||||
//Partial update support for 1.54, 2.13 RAK14000 b/w , 2.9 and 4.2
|
||||
//adafruitDisplay->setRotation(1);
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
} else {
|
||||
(void)adafruitDisplay;
|
||||
}
|
||||
}
|
||||
#elif defined(PCA10059)
|
||||
{
|
||||
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, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
}
|
||||
#elif defined(M5_COREINK)
|
||||
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(0);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "configuration.h"
|
||||
#if HAS_SCREEN
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
#include "GPS.h"
|
||||
@@ -32,16 +33,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "mesh/Channels.h"
|
||||
#include "mesh/generated/deviceonly.pb.h"
|
||||
#include "modules/TextMessageModule.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#endif
|
||||
|
||||
#ifdef OLED_RU
|
||||
#include "fonts/OLEDDisplayFontsRU.h"
|
||||
#endif
|
||||
|
||||
using namespace meshtastic; /** @todo remove */
|
||||
|
||||
namespace graphics
|
||||
@@ -49,7 +55,6 @@ namespace graphics
|
||||
|
||||
// This means the *visible* area (sh1106 can address 132, but shows 128 for example)
|
||||
#define IDLE_FRAMERATE 1 // in fps
|
||||
#define COMPASS_DIAM 44
|
||||
|
||||
// DEBUG
|
||||
#define NUM_EXTRA_FRAMES 3 // text message and debug frame
|
||||
@@ -61,6 +66,8 @@ static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
||||
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
||||
static char btPIN[16] = "888888";
|
||||
|
||||
uint32_t logo_timeout = 5000; // 4 seconds for EACH logo
|
||||
|
||||
// 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};
|
||||
|
||||
@@ -86,13 +93,17 @@ static uint16_t displayWidth, displayHeight;
|
||||
#define SCREEN_WIDTH displayWidth
|
||||
#define SCREEN_HEIGHT displayHeight
|
||||
|
||||
#ifdef HAS_EINK
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16
|
||||
#define FONT_MEDIUM ArialMT_Plain_24
|
||||
#define FONT_LARGE ArialMT_Plain_24
|
||||
#else
|
||||
#ifdef OLED_RU
|
||||
#define FONT_SMALL ArialMT_Plain_10_RU
|
||||
#else
|
||||
#define FONT_SMALL ArialMT_Plain_10
|
||||
#endif
|
||||
#define FONT_MEDIUM ArialMT_Plain_16
|
||||
#define FONT_LARGE ArialMT_Plain_24
|
||||
#endif
|
||||
@@ -101,12 +112,10 @@ static uint16_t displayWidth, displayHeight;
|
||||
|
||||
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
|
||||
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
|
||||
#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE)
|
||||
|
||||
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
|
||||
|
||||
#ifndef SCREEN_TRANSITION_MSECS
|
||||
#define SCREEN_TRANSITION_MSECS 300
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Draw the icon with extra info printed around the corners
|
||||
@@ -148,6 +157,55 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
drawIconScreen(region, display, state, x, y);
|
||||
}
|
||||
|
||||
static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// draw an xbm image.
|
||||
// Please note that everything that should be transitioned
|
||||
// needs to be drawn relative to x and y
|
||||
|
||||
// draw centered icon left to right and centered above the one line of app text
|
||||
display->drawXbm(x + (SCREEN_WIDTH - oemStore.oem_icon_width) / 2,
|
||||
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - oemStore.oem_icon_height) / 2 + 2, oemStore.oem_icon_width,
|
||||
oemStore.oem_icon_height, (const uint8_t *)oemStore.oem_icon_bits.bytes);
|
||||
|
||||
switch (oemStore.oem_font) {
|
||||
case 0:
|
||||
display->setFont(FONT_SMALL);
|
||||
break;
|
||||
case 2:
|
||||
display->setFont(FONT_LARGE);
|
||||
break;
|
||||
default:
|
||||
display->setFont(FONT_MEDIUM);
|
||||
break;
|
||||
}
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
const char *title = oemStore.oem_text;
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
// Draw region in upper left
|
||||
if (upperMsg)
|
||||
display->drawString(x + 0, y + 0, upperMsg);
|
||||
|
||||
// Draw version in upper right
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%s",
|
||||
xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
|
||||
screen->forceDisplay();
|
||||
|
||||
// FIXME - draw serial # somewhere?
|
||||
}
|
||||
|
||||
static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// Draw region in upper left
|
||||
const char *region = myRegion ? myRegion->name : NULL;
|
||||
drawOEMIconScreen(region, display, state, x, y);
|
||||
}
|
||||
|
||||
// Used on boot when a certificate is being created
|
||||
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
@@ -155,7 +213,7 @@ static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(64 + x, y, "Creating SSL certificate");
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#ifdef ARCH_ESP32
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
#endif
|
||||
@@ -168,7 +226,32 @@ static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_EINK
|
||||
// Used when booting without a region set
|
||||
static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
|
||||
display->drawString(64 + x, y + FONT_HEIGHT_SMALL, getDeviceName());
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
if ((millis() / 10000) % 2) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Flasher or CLI client.");
|
||||
} else {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information.");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "");
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_EINK
|
||||
/// Used on eink displays while in deep sleep
|
||||
static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
@@ -208,8 +291,13 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Enter this code");
|
||||
|
||||
display->setFont(FONT_LARGE);
|
||||
display->drawString(64 + x, 26 + y, btPIN);
|
||||
|
||||
auto displayPin = new String(btPIN);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawString(12 + x, 26 + y, displayPin->substring(0, 3));
|
||||
display->drawString(72 + x, 26 + y, displayPin->substring(3, 6));
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_SMALL);
|
||||
char buf[30];
|
||||
const char *name = "Name: ";
|
||||
@@ -226,6 +314,14 @@ static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
display->drawString(64 + x, 26 + y, "Shutting down...");
|
||||
}
|
||||
|
||||
static void drawFrameReboot(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(64 + x, 26 + y, "Rebooting...");
|
||||
}
|
||||
|
||||
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
@@ -238,9 +334,6 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
} else {
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
|
||||
}
|
||||
|
||||
// display->setFont(FONT_LARGE);
|
||||
// display->drawString(64 + x, 26 + y, btPIN);
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
@@ -256,14 +349,14 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->drawString(0 + x, 0 + y, tempBuf);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
|
||||
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
|
||||
static bool shouldDrawMessage(const MeshPacket *packet)
|
||||
{
|
||||
return packet->from != 0 && !radioConfig.preferences.range_test_module_enabled &&
|
||||
!radioConfig.preferences.store_forward_module_enabled;
|
||||
return packet->from != 0 && !moduleConfig.range_test.enabled &&
|
||||
!moduleConfig.store_forward.enabled;
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
@@ -377,7 +470,7 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
|
||||
// Draw GPS status summary
|
||||
static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
if (radioConfig.preferences.fixed_position) {
|
||||
if (config.position.fixed_position) {
|
||||
// GPS coordinates are currently fixed
|
||||
display->drawString(x - 1, y - 2, "Fixed GPS");
|
||||
return;
|
||||
@@ -416,15 +509,17 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
|
||||
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
String displayLine = "";
|
||||
if (!gps->getIsConnected() && !radioConfig.preferences.fixed_position) {
|
||||
if (!gps->getIsConnected() && !config.position.fixed_position) {
|
||||
// displayLine = "No GPS Module";
|
||||
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else if (!gps->getHasLock() && !radioConfig.preferences.fixed_position) {
|
||||
} else if (!gps->getHasLock() && !config.position.fixed_position) {
|
||||
// displayLine = "No GPS Lock";
|
||||
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else {
|
||||
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
|
||||
displayLine = "Altitude: " + String(geoCoord.getAltitude()) + "m";
|
||||
if (config.display.units == Config_DisplayConfig_DisplayUnits_IMPERIAL)
|
||||
displayLine = "Altitude: " + String(geoCoord.getAltitude() * METERS_TO_FEET) + "ft";
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
}
|
||||
}
|
||||
@@ -432,32 +527,32 @@ static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GP
|
||||
// Draw GPS status coordinates
|
||||
static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
auto gpsFormat = radioConfig.preferences.gps_format;
|
||||
auto gpsFormat = config.display.gps_format;
|
||||
String displayLine = "";
|
||||
|
||||
if (!gps->getIsConnected() && !radioConfig.preferences.fixed_position) {
|
||||
if (!gps->getIsConnected() && !config.position.fixed_position) {
|
||||
displayLine = "No GPS Module";
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else if (!gps->getHasLock() && !radioConfig.preferences.fixed_position) {
|
||||
} else if (!gps->getHasLock() && !config.position.fixed_position) {
|
||||
displayLine = "No GPS Lock";
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else {
|
||||
|
||||
if (gpsFormat != GpsCoordinateFormat_GpsFormatDMS) {
|
||||
if (gpsFormat != Config_DisplayConfig_GpsCoordinateFormat_DMS) {
|
||||
char coordinateLine[22];
|
||||
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
|
||||
if (gpsFormat == GpsCoordinateFormat_GpsFormatDec) { // Decimal Degrees
|
||||
if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_DEC) { // Decimal Degrees
|
||||
sprintf(coordinateLine, "%f %f", geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7);
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatUTM) { // Universal Transverse Mercator
|
||||
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_UTM) { // Universal Transverse Mercator
|
||||
sprintf(coordinateLine, "%2i%1c %06u %07u", geoCoord.getUTMZone(), geoCoord.getUTMBand(),
|
||||
geoCoord.getUTMEasting(), geoCoord.getUTMNorthing());
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatMGRS) { // Military Grid Reference System
|
||||
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_MGRS) { // Military Grid Reference System
|
||||
sprintf(coordinateLine, "%2i%1c %1c%1c %05u %05u", geoCoord.getMGRSZone(), geoCoord.getMGRSBand(),
|
||||
geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k(), geoCoord.getMGRSEasting(),
|
||||
geoCoord.getMGRSNorthing());
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatOLC) { // Open Location Code
|
||||
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_OLC) { // Open Location Code
|
||||
geoCoord.getOLCCode(coordinateLine);
|
||||
} else if (gpsFormat == GpsCoordinateFormat_GpsFormatOSGR) { // Ordnance Survey Grid Reference
|
||||
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_OSGR) { // Ordnance Survey Grid Reference
|
||||
if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region
|
||||
sprintf(coordinateLine, "%s", "Out of Boundary");
|
||||
else
|
||||
@@ -466,7 +561,7 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
|
||||
}
|
||||
|
||||
// If fixed position, display text "Fixed GPS" alternating with the coordinates.
|
||||
if (radioConfig.preferences.fixed_position) {
|
||||
if (config.position.fixed_position) {
|
||||
if ((millis() / 10000) % 2) {
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine);
|
||||
} else {
|
||||
@@ -504,7 +599,7 @@ class Point
|
||||
void rotate(float radian)
|
||||
{
|
||||
float cos = cosf(radian), sin = sinf(radian);
|
||||
float rx = x * cos - y * sin, ry = x * sin + y * cos;
|
||||
float rx = x * cos + y * sin, ry = -x * sin + y * cos;
|
||||
|
||||
x = rx;
|
||||
y = ry;
|
||||
@@ -518,8 +613,10 @@ class Point
|
||||
|
||||
void scale(float f)
|
||||
{
|
||||
//We use -f here to counter the flip that happens
|
||||
//on the y axis when drawing and rotating on screen
|
||||
x *= f;
|
||||
y *= f;
|
||||
y *= -f;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -567,6 +664,26 @@ static bool hasPosition(NodeInfo *n)
|
||||
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
|
||||
}
|
||||
|
||||
static uint16_t getCompassDiam(OLEDDisplay *display)
|
||||
{
|
||||
uint16_t diam = 0;
|
||||
// get the smaller of the 2 dimensions and subtract 20
|
||||
if(display->getWidth() > display->getHeight()) {
|
||||
diam = display->getHeight();
|
||||
// if 2/3 of the other size would be smaller, use that
|
||||
if (diam > (display->getWidth() * 2 / 3)) {
|
||||
diam = display->getWidth() * 2 / 3;
|
||||
}
|
||||
} else {
|
||||
diam = display->getWidth();
|
||||
if (diam > (display->getHeight() * 2 / 3)) {
|
||||
diam = display->getHeight() * 2 / 3;
|
||||
}
|
||||
}
|
||||
|
||||
return diam - 20;
|
||||
};
|
||||
|
||||
/// We will skip one node - the one for us, so we just blindly loop over all
|
||||
/// nodes
|
||||
static size_t nodeIndex;
|
||||
@@ -583,7 +700,7 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
arrowPoints[i]->rotate(headingRadian);
|
||||
arrowPoints[i]->scale(COMPASS_DIAM * 0.6);
|
||||
arrowPoints[i]->scale(getCompassDiam(display) * 0.6);
|
||||
arrowPoints[i]->translate(compassX, compassY);
|
||||
}
|
||||
drawLine(display, tip, tail);
|
||||
@@ -591,16 +708,21 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp
|
||||
drawLine(display, rightArrow, tip);
|
||||
}
|
||||
|
||||
// Draw the compass heading
|
||||
static void drawCompassHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading)
|
||||
// Draw north
|
||||
static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading)
|
||||
{
|
||||
Point N1(-0.04f, -0.65f), N2(0.04f, -0.65f);
|
||||
Point N3(-0.04f, -0.55f), N4(0.04f, -0.55f);
|
||||
//If north is supposed to be at the top of the compass we want rotation to be +0
|
||||
if(config.display.compass_north_top)
|
||||
myHeading = -0;
|
||||
|
||||
Point N1(-0.04f, 0.65f), N2(0.04f, 0.65f);
|
||||
Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f);
|
||||
Point *rosePoints[] = {&N1, &N2, &N3, &N4};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
rosePoints[i]->rotate(myHeading);
|
||||
rosePoints[i]->scale(-1 * COMPASS_DIAM);
|
||||
// North on compass will be negative of heading
|
||||
rosePoints[i]->rotate(-myHeading);
|
||||
rosePoints[i]->scale(getCompassDiam(display));
|
||||
rosePoints[i]->translate(compassX, compassY);
|
||||
}
|
||||
drawLine(display, N1, N3);
|
||||
@@ -646,8 +768,18 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
|
||||
else if (agoSecs < 120 * 60) // last 2 hrs
|
||||
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
|
||||
else
|
||||
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
|
||||
else {
|
||||
|
||||
uint32_t hours_in_month = 730;
|
||||
|
||||
// Only show hours ago if it's been less than 6 months. Otherwise, we may have bad
|
||||
// data.
|
||||
if ((agoSecs / 60 / 60) < (hours_in_month * 6)) {
|
||||
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
|
||||
} else {
|
||||
snprintf(lastStr, sizeof(lastStr), "unknown age");
|
||||
}
|
||||
}
|
||||
|
||||
static char distStr[20];
|
||||
strcpy(distStr, "? km"); // might not have location data
|
||||
@@ -655,13 +787,13 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||
|
||||
// coordinates for the center of the compass/circle
|
||||
int16_t compassX = x + SCREEN_WIDTH - COMPASS_DIAM / 2 - 5, compassY = y + SCREEN_HEIGHT / 2;
|
||||
int16_t compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5, compassY = y + SCREEN_HEIGHT / 2;
|
||||
bool hasNodeHeading = false;
|
||||
|
||||
if (ourNode && hasPosition(ourNode)) {
|
||||
Position &op = ourNode->position;
|
||||
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
drawCompassHeading(display, compassX, compassY, myHeading);
|
||||
drawCompassNorth(display, compassX, compassY, myHeading);
|
||||
|
||||
if (hasPosition(node)) {
|
||||
// display direction toward node
|
||||
@@ -669,17 +801,26 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
Position &p = node->position;
|
||||
float d =
|
||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
|
||||
|
||||
// FIXME, also keep the guess at the operators heading and add/substract
|
||||
// it. currently we don't do this and instead draw north up only.
|
||||
if (config.display.units == Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
if (d < (2 * MILES_TO_FEET))
|
||||
snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f mi", d * METERS_TO_FEET / MILES_TO_FEET);
|
||||
} else {
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
|
||||
}
|
||||
|
||||
float bearingToOther =
|
||||
GeoCoord::bearing(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
float headingRadian = bearingToOther - myHeading;
|
||||
drawNodeHeading(display, compassX, compassY, headingRadian);
|
||||
GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
// If the top of the compass is a static north then bearingToOther can be drawn on the compass directly
|
||||
// If the top of the compass is not a static north we need adjust bearingToOther based on heading
|
||||
if(!config.display.compass_north_top)
|
||||
bearingToOther -= myHeading;
|
||||
drawNodeHeading(display, compassX, compassY, bearingToOther);
|
||||
}
|
||||
}
|
||||
if (!hasNodeHeading)
|
||||
@@ -687,7 +828,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
// Debug info for gps lock errors
|
||||
// DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
|
||||
display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
|
||||
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
|
||||
display->drawCircle(compassX, compassY, getCompassDiam(display) / 2);
|
||||
|
||||
// Must be after distStr is populated
|
||||
drawColumns(display, x, y, fields);
|
||||
@@ -716,19 +857,33 @@ void _screen_header()
|
||||
}
|
||||
#endif
|
||||
|
||||
// #ifdef RAK4630
|
||||
// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl),
|
||||
// dispdev_oled(address, sda, scl), ui(&dispdev)
|
||||
// {
|
||||
// address_found = address;
|
||||
// cmdQueue.setReader(this);
|
||||
// if (screen_found) {
|
||||
// (void)dispdev;
|
||||
// AutoOLEDWire dispdev = dispdev_oled;
|
||||
// (void)ui;
|
||||
// OLEDDisplayUi ui(&dispdev);
|
||||
// }
|
||||
// }
|
||||
// #else
|
||||
Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev)
|
||||
{
|
||||
address_found = address;
|
||||
cmdQueue.setReader(this);
|
||||
}
|
||||
|
||||
// #endif
|
||||
/**
|
||||
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just
|
||||
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
|
||||
*/
|
||||
void Screen::doDeepSleep()
|
||||
{
|
||||
#ifdef HAS_EINK
|
||||
#ifdef USE_EINK
|
||||
static FrameCallback sleepFrames[] = {drawSleepScreen};
|
||||
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
|
||||
ui.setFrames(sleepFrames, sleepFrameCount);
|
||||
@@ -766,19 +921,16 @@ void Screen::setup()
|
||||
useDisplay = true;
|
||||
|
||||
#ifdef AutoOLEDWire_h
|
||||
dispdev.setDetected(screen_model);
|
||||
dispdev.setDetected(screen_model);
|
||||
#endif
|
||||
|
||||
// I think this is not needed - redundant with ui.init
|
||||
// dispdev.resetOrientation();
|
||||
|
||||
// Initialising the UI will init the display too.
|
||||
ui.init();
|
||||
|
||||
displayWidth = dispdev.width();
|
||||
displayHeight = dispdev.height();
|
||||
|
||||
ui.setTimePerTransition(SCREEN_TRANSITION_MSECS);
|
||||
ui.setTimePerTransition(0);
|
||||
|
||||
ui.setIndicatorPosition(BOTTOM);
|
||||
// Defines where the first frame is located in the bar.
|
||||
@@ -792,6 +944,9 @@ void Screen::setup()
|
||||
// Set the utf8 conversion function
|
||||
dispdev.setFontTableLookupFunction(customFontTableLookup);
|
||||
|
||||
if (strlen(oemStore.oem_text) > 0)
|
||||
logo_timeout *= 2;
|
||||
|
||||
// Add frames.
|
||||
static FrameCallback bootFrames[] = {drawBootScreen};
|
||||
static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]);
|
||||
@@ -807,8 +962,12 @@ void Screen::setup()
|
||||
|
||||
#ifdef SCREEN_MIRROR
|
||||
dispdev.mirrorScreen();
|
||||
#elif defined(SCREEN_FLIP_VERTICALLY)
|
||||
dispdev.flipScreenVertically();
|
||||
#else
|
||||
// Standard behaviour is to FLIP the screen (needed on T-Beam). If this config item is set, unflip it, and thereby logically flip it.
|
||||
// If you have a headache now, you're welcome.
|
||||
if (!config.display.flip_screen) {
|
||||
dispdev.flipScreenVertically();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get our hardware ID
|
||||
@@ -820,9 +979,12 @@ void Screen::setup()
|
||||
handleSetOn(true);
|
||||
|
||||
// On some ssd1306 clones, the first draw command is discarded, so draw it
|
||||
// twice initially.
|
||||
// twice initially. Skip this for EINK Displays to save a few seconds during boot
|
||||
ui.update();
|
||||
#ifndef USE_EINK
|
||||
ui.update();
|
||||
#endif
|
||||
serialSinceMsec = millis();
|
||||
|
||||
// Subscribe to status updates
|
||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||
@@ -838,7 +1000,7 @@ void Screen::setup()
|
||||
void Screen::forceDisplay()
|
||||
{
|
||||
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
|
||||
#ifdef HAS_EINK
|
||||
#ifdef USE_EINK
|
||||
dispdev.forceDisplay();
|
||||
#endif
|
||||
}
|
||||
@@ -853,15 +1015,38 @@ int32_t Screen::runOnce()
|
||||
return RUN_SAME;
|
||||
}
|
||||
|
||||
// Show boot screen for first 3 seconds, then switch to normal operation.
|
||||
// Show boot screen for first logo_timeout seconds, then switch to normal operation.
|
||||
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
|
||||
static bool showingBootScreen = true;
|
||||
if (showingBootScreen && (millis() > (5000 + serialSinceMsec))) {
|
||||
if (showingBootScreen && (millis() > (logo_timeout + serialSinceMsec))) {
|
||||
DEBUG_MSG("Done with boot screen...\n");
|
||||
stopBootScreen();
|
||||
showingBootScreen = false;
|
||||
}
|
||||
|
||||
// If we have an OEM Boot screen, toggle after logo_timeout seconds
|
||||
if (strlen(oemStore.oem_text) > 0) {
|
||||
static bool showingOEMBootScreen = true;
|
||||
if (showingOEMBootScreen && (millis() > ((logo_timeout / 2) + serialSinceMsec))) {
|
||||
DEBUG_MSG("Switch to OEM screen...\n");
|
||||
// Change frames.
|
||||
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
|
||||
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
|
||||
ui.setFrames(bootOEMFrames, bootOEMFrameCount);
|
||||
ui.update();
|
||||
#ifndef USE_EINK
|
||||
ui.update();
|
||||
#endif
|
||||
showingOEMBootScreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_WELCOME_UNSET
|
||||
if (showingNormalScreen && config.lora.region == Config_LoRaConfig_RegionCode_UNSET) {
|
||||
setWelcomeFrames();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Process incoming commands.
|
||||
for (;;) {
|
||||
ScreenCmd cmd;
|
||||
@@ -895,6 +1080,9 @@ int32_t Screen::runOnce()
|
||||
case Cmd::START_SHUTDOWN_SCREEN:
|
||||
handleShutdownScreen();
|
||||
break;
|
||||
case Cmd::START_REBOOT_SCREEN:
|
||||
handleRebootScreen();
|
||||
break;
|
||||
default:
|
||||
DEBUG_MSG("BUG: invalid cmd\n");
|
||||
}
|
||||
@@ -915,13 +1103,8 @@ int32_t Screen::runOnce()
|
||||
// otherwise that breaks animations.
|
||||
if (targetFramerate != IDLE_FRAMERATE && ui.getUiState()->frameState == FIXED) {
|
||||
// oldFrameState = ui.getUiState()->frameState;
|
||||
DEBUG_MSG("Setting idle framerate\n");
|
||||
targetFramerate = IDLE_FRAMERATE;
|
||||
|
||||
#ifndef NO_ESP32
|
||||
setCPUFast(false); // Turn up the CPU to improve screen animations
|
||||
#endif
|
||||
|
||||
ui.setTargetFPS(targetFramerate);
|
||||
forceDisplay();
|
||||
}
|
||||
@@ -930,8 +1113,8 @@ int32_t Screen::runOnce()
|
||||
// standard screen switching is stopped.
|
||||
if (showingNormalScreen) {
|
||||
// standard screen loop handling here
|
||||
if (radioConfig.preferences.auto_screen_carousel_secs > 0 &&
|
||||
(millis() - lastScreenTransition) > (radioConfig.preferences.auto_screen_carousel_secs * 1000)) {
|
||||
if (config.display.auto_screen_carousel_secs > 0 &&
|
||||
(millis() - lastScreenTransition) > (config.display.auto_screen_carousel_secs * 1000)) {
|
||||
DEBUG_MSG("LastScreenTransition exceeded %ums transitioning to next frame\n", (millis() - lastScreenTransition));
|
||||
handleOnPress();
|
||||
}
|
||||
@@ -975,6 +1158,20 @@ void Screen::setSSLFrames()
|
||||
}
|
||||
}
|
||||
|
||||
/* show a message that the SSL cert is being built
|
||||
* it is expected that this will be used during the boot phase */
|
||||
void Screen::setWelcomeFrames()
|
||||
{
|
||||
if (address_found) {
|
||||
// DEBUG_MSG("showing Welcome frames\n");
|
||||
ui.disableAllIndicators();
|
||||
|
||||
static FrameCallback welcomeFrames[] = {drawWelcomeScreen};
|
||||
ui.setFrames(welcomeFrames, 1);
|
||||
ui.update();
|
||||
}
|
||||
}
|
||||
|
||||
// restore our regular frame list
|
||||
void Screen::setFrames()
|
||||
{
|
||||
@@ -1029,7 +1226,7 @@ void Screen::setFrames()
|
||||
// call a method on debugInfoScreen object (for more details)
|
||||
normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#ifdef ARCH_ESP32
|
||||
if (isWifiAvailable()) {
|
||||
// call a method on debugInfoScreen object (for more details)
|
||||
normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline;
|
||||
@@ -1073,6 +1270,18 @@ void Screen::handleShutdownScreen()
|
||||
setFastFramerate();
|
||||
}
|
||||
|
||||
void Screen::handleRebootScreen()
|
||||
{
|
||||
DEBUG_MSG("showing reboot screen\n");
|
||||
showingNormalScreen = false;
|
||||
|
||||
static FrameCallback rebootFrames[] = {drawFrameReboot};
|
||||
|
||||
ui.disableAllIndicators();
|
||||
ui.setFrames(rebootFrames, 1);
|
||||
setFastFramerate();
|
||||
}
|
||||
|
||||
void Screen::handleStartFirmwareUpdateScreen()
|
||||
{
|
||||
DEBUG_MSG("showing firmware screen\n");
|
||||
@@ -1119,7 +1328,6 @@ void Screen::handleOnPress()
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.nextFrame();
|
||||
DEBUG_MSG("Setting LastScreenTransition\n");
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
@@ -1131,15 +1339,9 @@ void Screen::handleOnPress()
|
||||
|
||||
void Screen::setFastFramerate()
|
||||
{
|
||||
DEBUG_MSG("Setting fast framerate\n");
|
||||
|
||||
// We are about to start a transition so speed up fps
|
||||
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
||||
|
||||
#ifndef NO_ESP32
|
||||
setCPUFast(true); // Turn up the CPU to improve screen animations
|
||||
#endif
|
||||
|
||||
ui.setTargetFPS(targetFramerate);
|
||||
setInterval(0); // redraw ASAP
|
||||
runASAP = true;
|
||||
@@ -1191,9 +1393,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
// Jm
|
||||
void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
#ifdef HAS_WIFI
|
||||
const char *wifiName = radioConfig.preferences.wifi_ssid;
|
||||
const char *wifiPsw = radioConfig.preferences.wifi_password;
|
||||
#if HAS_WIFI
|
||||
const char *wifiName = config.network.wifi_ssid;
|
||||
|
||||
displayedNodeNum = 0; // Not currently showing a node pane
|
||||
|
||||
@@ -1202,11 +1403,7 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
// The coordinates define the left starting point of the text
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
if (isSoftAPForced()) {
|
||||
display->drawString(x, y, String("WiFi: Software AP (Admin)"));
|
||||
} else if (radioConfig.preferences.wifi_ap_mode) {
|
||||
display->drawString(x, y, String("WiFi: Software AP"));
|
||||
} else if (WiFi.status() != WL_CONNECTED) {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
display->drawString(x, y, String("WiFi: Not Connected"));
|
||||
} else {
|
||||
display->drawString(x, y, String("WiFi: Connected"));
|
||||
@@ -1227,25 +1424,14 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
- WL_NO_SHIELD: assigned when no WiFi shield is present;
|
||||
|
||||
*/
|
||||
if (WiFi.status() == WL_CONNECTED || isSoftAPForced() || radioConfig.preferences.wifi_ap_mode) {
|
||||
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str()));
|
||||
|
||||
// Number of connections to the AP. Default max for the esp32 is 4
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("(" + String(WiFi.softAPgetStationNum()) + "/4)"),
|
||||
y + FONT_HEIGHT_SMALL * 1, "(" + String(WiFi.softAPgetStationNum()) + "/4)");
|
||||
} else {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
|
||||
}
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
|
||||
} else if (WiFi.status() == WL_NO_SSID_AVAIL) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");
|
||||
} else if (WiFi.status() == WL_CONNECTION_LOST) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Lost");
|
||||
} else if (WiFi.status() == WL_CONNECT_FAILED) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
|
||||
//} else if (WiFi.status() == WL_DISCONNECTED) {
|
||||
// display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disconnected");
|
||||
} else if (WiFi.status() == WL_IDLE_STATUS) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting");
|
||||
} else {
|
||||
@@ -1312,24 +1498,8 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
}
|
||||
}
|
||||
|
||||
if (isSoftAPForced()) {
|
||||
if ((millis() / 10000) % 2) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: meshtasticAdmin");
|
||||
} else {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: 12345678");
|
||||
}
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
|
||||
|
||||
} else {
|
||||
if (radioConfig.preferences.wifi_ap_mode) {
|
||||
if ((millis() / 10000) % 2) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
|
||||
} else {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: " + String(wifiPsw));
|
||||
}
|
||||
} else {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
|
||||
}
|
||||
}
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 3, "http://meshtastic.local");
|
||||
|
||||
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
|
||||
@@ -1366,23 +1536,32 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
}
|
||||
|
||||
auto mode = "";
|
||||
|
||||
if (channels.getPrimary().modem_config == 0) {
|
||||
mode = "VLongSlow";
|
||||
} else if (channels.getPrimary().modem_config == 1) {
|
||||
mode = "LongSlow";
|
||||
} else if (channels.getPrimary().modem_config == 2) {
|
||||
mode = "LongFast";
|
||||
} else if (channels.getPrimary().modem_config == 3) {
|
||||
mode = "MidSlow";
|
||||
} else if (channels.getPrimary().modem_config == 4) {
|
||||
mode = "MidFast";
|
||||
} else if (channels.getPrimary().modem_config == 5) {
|
||||
mode = "ShortSlow";
|
||||
} else if (channels.getPrimary().modem_config == 6) {
|
||||
mode = "ShortFast";
|
||||
} else {
|
||||
|
||||
switch (config.lora.modem_preset) {
|
||||
case Config_LoRaConfig_ModemPreset_SHORT_SLOW:
|
||||
mode = "ShortS";
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_SHORT_FAST:
|
||||
mode = "ShortF";
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
|
||||
mode = "MedS";
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
|
||||
mode = "MedF";
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_LONG_SLOW:
|
||||
mode = "LongS";
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_LONG_FAST:
|
||||
mode = "LongF";
|
||||
break;
|
||||
case Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
|
||||
mode = "VeryL";
|
||||
break;
|
||||
default:
|
||||
mode = "Custom";
|
||||
break;
|
||||
}
|
||||
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
|
||||
@@ -1409,7 +1588,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
else
|
||||
uptime += String(seconds) + "s ";
|
||||
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet);
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
|
||||
if (rtc_sec > 0) {
|
||||
long hms = rtc_sec % SEC_PER_DAY;
|
||||
// hms += tz.tz_dsttime * SEC_PER_HOUR;
|
||||
@@ -1432,11 +1611,11 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
// Display Channel Utilization
|
||||
char chUtil[13];
|
||||
sprintf(chUtil, "ChUtil %2.0f%%", airTime->channelUtilizationPercent());
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil),
|
||||
y + FONT_HEIGHT_SMALL * 1, chUtil);
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
|
||||
|
||||
// Line 3
|
||||
if (radioConfig.preferences.gps_format != GpsCoordinateFormat_GpsFormatDMS) // if DMS then don't draw altitude
|
||||
if (config.display.gps_format !=
|
||||
Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
|
||||
drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
||||
|
||||
// Line 4
|
||||
@@ -1452,6 +1631,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
// adjust Brightness cycle trough 1 to 254 as long as attachDuringLongPress is true
|
||||
void Screen::adjustBrightness()
|
||||
{
|
||||
if (!useDisplay)
|
||||
return;
|
||||
|
||||
if (brightness == 254) {
|
||||
brightness = 0;
|
||||
} else {
|
||||
@@ -1491,16 +1673,13 @@ int Screen::handleTextMessage(const MeshPacket *packet)
|
||||
int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||
{
|
||||
if (showingNormalScreen) {
|
||||
if (event->frameChanged)
|
||||
{
|
||||
if (event->frameChanged) {
|
||||
setFrames(); // Regen the list of screens (will show new text message)
|
||||
}
|
||||
else if (event->needRedraw)
|
||||
{
|
||||
} else if (event->needRedraw) {
|
||||
setFastFramerate();
|
||||
// TODO: We might also want switch to corresponding frame,
|
||||
// but we don't know the exact frame number.
|
||||
//ui.switchToFrame(0);
|
||||
// ui.switchToFrame(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,3 +1687,5 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
#endif // HAS_SCREEN
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef NO_SCREEN
|
||||
#include "configuration.h"
|
||||
|
||||
#if !HAS_SCREEN
|
||||
#include "power.h"
|
||||
namespace graphics
|
||||
{
|
||||
// Noop class for boards without screen.
|
||||
class Screen
|
||||
{
|
||||
public:
|
||||
Screen(char){}
|
||||
explicit Screen(char){}
|
||||
void onPress() {}
|
||||
void setup() {}
|
||||
void setOn(bool) {}
|
||||
@@ -15,6 +18,9 @@ class Screen
|
||||
void adjustBrightness(){}
|
||||
void doDeepSleep() {}
|
||||
void forceDisplay() {}
|
||||
void startBluetoothPinScreen(uint32_t pin) {}
|
||||
void stopBluetoothPinScreen() {}
|
||||
void startRebootScreen() {}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,6 +33,10 @@ class Screen
|
||||
|
||||
#ifdef USE_ST7567
|
||||
#include <ST7567Wire.h>
|
||||
#elif defined(USE_SH1106)
|
||||
#include <SH1106Wire.h>
|
||||
#elif defined(USE_SSD1306)
|
||||
#include <SSD1306Wire.h>
|
||||
#else
|
||||
// the SH1106/SSD1306 variant is auto-detected
|
||||
#include <AutoOLEDWire.h>
|
||||
@@ -47,6 +57,16 @@ class Screen
|
||||
#define BRIGHTNESS_DEFAULT 150
|
||||
#endif
|
||||
|
||||
// Meters to feet conversion
|
||||
#ifndef METERS_TO_FEET
|
||||
#define METERS_TO_FEET 3.28
|
||||
#endif
|
||||
|
||||
// Feet to miles conversion
|
||||
#ifndef MILES_TO_FEET
|
||||
#define MILES_TO_FEET 5280
|
||||
#endif
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
@@ -111,8 +131,7 @@ class Screen : public concurrency::OSThread
|
||||
void setOn(bool on)
|
||||
{
|
||||
if (!on)
|
||||
handleSetOn(
|
||||
false); // We handle off commands immediately, because they might be called because the CPU is shutting down
|
||||
handleSetOn(false); // We handle off commands immediately, because they might be called because the CPU is shutting down
|
||||
else
|
||||
enqueueCmd(ScreenCmd{.cmd = on ? Cmd::SET_ON : Cmd::SET_OFF});
|
||||
}
|
||||
@@ -158,6 +177,13 @@ class Screen : public concurrency::OSThread
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
void startRebootScreen()
|
||||
{
|
||||
ScreenCmd cmd;
|
||||
cmd.cmd = Cmd::START_REBOOT_SCREEN;
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
/// Stops showing the bluetooth PIN screen.
|
||||
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
|
||||
|
||||
@@ -195,19 +221,34 @@ class Screen : public concurrency::OSThread
|
||||
uint8_t last = LASTCHAR; // get last char
|
||||
LASTCHAR = ch;
|
||||
|
||||
switch (last) { // conversion depnding on first UTF8-character
|
||||
case 0xC2: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)ch;
|
||||
}
|
||||
case 0xC3: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)(ch | 0xC0);
|
||||
}
|
||||
switch (last) { // conversion depending on first UTF8-character
|
||||
case 0xC2: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)ch;
|
||||
}
|
||||
case 0xC3: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)(ch | 0xC0);
|
||||
}
|
||||
// map UTF-8 cyrillic chars to it Windows-1251 (CP-1251) ASCII codes
|
||||
// note: in this case we must use compatible font - provided ArialMT_Plain_10/16/24 by 'ThingPulse/esp8266-oled-ssd1306' library
|
||||
// have empty chars for non-latin ASCII symbols
|
||||
case 0xD0: {
|
||||
SKIPREST = false;
|
||||
if (ch == 129) return (uint8_t)(168); // Ё
|
||||
if (ch > 143 && ch < 192) return (uint8_t)(ch + 48);
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
SKIPREST = false;
|
||||
if (ch == 145) return (uint8_t)(184); // ё
|
||||
if (ch > 127 && ch < 144) return (uint8_t)(ch + 112);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We want to strip out prefix chars for two-byte char formats
|
||||
if (ch == 0xC2 || ch == 0xC3 || ch == 0x82)
|
||||
if (ch == 0xC2 || ch == 0xC3 || ch == 0x82 || ch == 0xD0 || ch == 0xD1)
|
||||
return (uint8_t)0;
|
||||
|
||||
// If we already returned an unconvertable-character symbol for this unconvertable-character sequence, return NULs for the
|
||||
@@ -235,6 +276,8 @@ class Screen : public concurrency::OSThread
|
||||
/// Draws our SSL cert screen during boot (called from WebServer)
|
||||
void setSSLFrames();
|
||||
|
||||
void setWelcomeFrames();
|
||||
|
||||
protected:
|
||||
/// Updates the UI.
|
||||
//
|
||||
@@ -269,6 +312,7 @@ class Screen : public concurrency::OSThread
|
||||
void handlePrint(const char *text);
|
||||
void handleStartFirmwareUpdateScreen();
|
||||
void handleShutdownScreen();
|
||||
void handleRebootScreen();
|
||||
/// Rebuilds our list of frames (screens) to default ones.
|
||||
void setFrames();
|
||||
|
||||
@@ -295,11 +339,18 @@ class Screen : public concurrency::OSThread
|
||||
/// Holds state for debug information
|
||||
DebugInfo debugInfo;
|
||||
|
||||
/// Display device
|
||||
/** FIXME cleanup display abstraction */
|
||||
#ifdef ST7735_CS
|
||||
/// Display device
|
||||
|
||||
// #ifdef RAK4630
|
||||
// EInkDisplay dispdev;
|
||||
// AutoOLEDWire dispdev_oled;
|
||||
#ifdef USE_SH1106
|
||||
SH1106Wire dispdev;
|
||||
#elif defined(USE_SSD1306)
|
||||
SSD1306Wire dispdev;
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
|
||||
TFTDisplay dispdev;
|
||||
#elif defined(HAS_EINK)
|
||||
#elif defined(USE_EINK)
|
||||
EInkDisplay dispdev;
|
||||
#elif defined(USE_ST7567)
|
||||
ST7567Wire dispdev;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef ST7735_CS
|
||||
#if defined(ST7735_CS) || defined(ILI9341_DRIVER)
|
||||
#include "SPILock.h"
|
||||
#include "TFTDisplay.h"
|
||||
#include <SPI.h>
|
||||
@@ -10,7 +10,11 @@ static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.
|
||||
|
||||
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl)
|
||||
{
|
||||
setGeometry(GEOMETRY_RAWMODE, 160, 80);
|
||||
#ifdef SCREEN_ROTATE
|
||||
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);
|
||||
#else
|
||||
setGeometry(GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Write the buffer to the display memory
|
||||
@@ -18,15 +22,23 @@ void TFTDisplay::display(void)
|
||||
{
|
||||
concurrency::LockGuard g(spiLock);
|
||||
|
||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
|
||||
for (uint8_t y = 0; y < displayHeight; y++) {
|
||||
for (uint8_t x = 0; x < displayWidth; x++) {
|
||||
uint16_t x,y;
|
||||
|
||||
for (y = 0; y < displayHeight; y++) {
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||
auto b = buffer[x + (y / 8) * displayWidth];
|
||||
auto isset = b & (1 << (y & 7));
|
||||
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
|
||||
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
if (isset != dblbuf_isset) {
|
||||
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy the Buffer to the Back Buffer
|
||||
for (y = 0; y < (displayHeight / 8); y++) {
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
uint16_t pos = x + y * displayWidth;
|
||||
buffer_back[pos] = buffer[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,21 +50,34 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
// Drop all commands to device (we just update the buffer)
|
||||
}
|
||||
|
||||
void TFTDisplay::setDetected(uint8_t detected)
|
||||
{
|
||||
(void)detected;
|
||||
}
|
||||
|
||||
// Connect to the display
|
||||
bool TFTDisplay::connect()
|
||||
{
|
||||
concurrency::LockGuard g(spiLock);
|
||||
DEBUG_MSG("Doing TFT init\n");
|
||||
|
||||
#ifdef TFT_BL
|
||||
digitalWrite(TFT_BL, HIGH);
|
||||
pinMode(TFT_BL, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef ST7735_BACKLIGHT_EN
|
||||
digitalWrite(ST7735_BACKLIGHT_EN, HIGH);
|
||||
pinMode(ST7735_BACKLIGHT_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
tft.init();
|
||||
#ifdef M5STACK
|
||||
tft.setRotation(1); // M5Stack has the TFT in landscape
|
||||
#else
|
||||
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||
#endif
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
// tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,12 @@ class TFTDisplay : public OLEDDisplay
|
||||
|
||||
// Write the buffer to the display memory
|
||||
virtual void display(void) override;
|
||||
|
||||
/**
|
||||
* shim to make the abstraction happy
|
||||
*
|
||||
*/
|
||||
void setDetected(uint8_t detected);
|
||||
|
||||
protected:
|
||||
// the header size of the buffer used, e.g. for the SPI command header
|
||||
|
||||
426
src/graphics/fonts/OLEDDisplayFontsRU.cpp
Normal file
426
src/graphics/fonts/OLEDDisplayFontsRU.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
#include "OLEDDisplayFontsRU.h"
|
||||
|
||||
// Font generated or edited with the glyphEditor
|
||||
const uint8_t ArialMT_Plain_10_RU[] 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, 0x0A, 0x06, // 165
|
||||
0x03, 0x9C, 0x04, 0x03, // 166
|
||||
0x03, 0xA0, 0x0A, 0x06, // 167
|
||||
0x03, 0xAA, 0x0C, 0x07, // 168
|
||||
0x03, 0xB6, 0x0D, 0x08, // 169
|
||||
0x03, 0xC3, 0x07, 0x05, // 170
|
||||
0x03, 0xCA, 0x0A, 0x06, // 171
|
||||
0x03, 0xD4, 0x09, 0x06, // 172
|
||||
0x03, 0xDD, 0x03, 0x03, // 173
|
||||
0x03, 0xE0, 0x0D, 0x08, // 174
|
||||
0x03, 0xED, 0x0B, 0x07, // 175
|
||||
0x03, 0xF8, 0x07, 0x05, // 176
|
||||
0x03, 0xFF, 0x0A, 0x06, // 177
|
||||
0x04, 0x09, 0x05, 0x04, // 178
|
||||
0x04, 0x0E, 0x05, 0x04, // 179
|
||||
0x04, 0x13, 0x05, 0x04, // 180
|
||||
0x04, 0x18, 0x0A, 0x06, // 181
|
||||
0x04, 0x22, 0x09, 0x06, // 182
|
||||
0x04, 0x2B, 0x03, 0x03, // 183
|
||||
0x04, 0x2E, 0x0B, 0x07, // 184
|
||||
0x04, 0x39, 0x0B, 0x07, // 185
|
||||
0x04, 0x44, 0x07, 0x05, // 186
|
||||
0x04, 0x4B, 0x0A, 0x06, // 187
|
||||
0x04, 0x55, 0x10, 0x09, // 188
|
||||
0x04, 0x65, 0x10, 0x09, // 189
|
||||
0x04, 0x75, 0x10, 0x09, // 190
|
||||
0x04, 0x85, 0x0A, 0x06, // 191
|
||||
0x04, 0x8F, 0x0C, 0x07, // 192
|
||||
0x04, 0x9B, 0x0C, 0x07, // 193
|
||||
0x04, 0xA7, 0x0C, 0x07, // 194
|
||||
0x04, 0xB3, 0x0B, 0x07, // 195
|
||||
0x04, 0xBE, 0x0C, 0x07, // 196
|
||||
0x04, 0xCA, 0x0C, 0x07, // 197
|
||||
0x04, 0xD6, 0x0C, 0x07, // 198
|
||||
0x04, 0xE2, 0x0C, 0x07, // 199
|
||||
0x04, 0xEE, 0x0C, 0x07, // 200
|
||||
0x04, 0xFA, 0x0C, 0x07, // 201
|
||||
0x05, 0x06, 0x0C, 0x07, // 202
|
||||
0x05, 0x12, 0x0C, 0x07, // 203
|
||||
0x05, 0x1E, 0x0C, 0x07, // 204
|
||||
0x05, 0x2A, 0x0C, 0x07, // 205
|
||||
0x05, 0x36, 0x0C, 0x07, // 206
|
||||
0x05, 0x42, 0x0C, 0x07, // 207
|
||||
0x05, 0x4E, 0x0B, 0x07, // 208
|
||||
0x05, 0x59, 0x0C, 0x07, // 209
|
||||
0x05, 0x65, 0x0B, 0x07, // 210
|
||||
0x05, 0x70, 0x0C, 0x07, // 211
|
||||
0x05, 0x7C, 0x0B, 0x07, // 212
|
||||
0x05, 0x87, 0x0C, 0x07, // 213
|
||||
0x05, 0x93, 0x0C, 0x07, // 214
|
||||
0x05, 0x9F, 0x0C, 0x07, // 215
|
||||
0x05, 0xAB, 0x0C, 0x07, // 216
|
||||
0x05, 0xB7, 0x0E, 0x08, // 217
|
||||
0x05, 0xC5, 0x0C, 0x07, // 218
|
||||
0x05, 0xD1, 0x0C, 0x07, // 219
|
||||
0x05, 0xDD, 0x0C, 0x07, // 220
|
||||
0x05, 0xE9, 0x0C, 0x07, // 221
|
||||
0x05, 0xF5, 0x0C, 0x07, // 222
|
||||
0x06, 0x01, 0x0C, 0x07, // 223
|
||||
0x06, 0x0D, 0x0C, 0x07, // 224
|
||||
0x06, 0x19, 0x0C, 0x07, // 225
|
||||
0x06, 0x25, 0x0C, 0x07, // 226
|
||||
0x06, 0x31, 0x0B, 0x07, // 227
|
||||
0x06, 0x3C, 0x0C, 0x07, // 228
|
||||
0x06, 0x48, 0x0B, 0x07, // 229
|
||||
0x06, 0x53, 0x0C, 0x07, // 230
|
||||
0x06, 0x5F, 0x0C, 0x07, // 231
|
||||
0x06, 0x6B, 0x0C, 0x07, // 232
|
||||
0x06, 0x77, 0x0C, 0x07, // 233
|
||||
0x06, 0x83, 0x0C, 0x07, // 234
|
||||
0x06, 0x8F, 0x0C, 0x07, // 235
|
||||
0x06, 0x9B, 0x0C, 0x07, // 236
|
||||
0x06, 0xA7, 0x0C, 0x07, // 237
|
||||
0x06, 0xB3, 0x0C, 0x07, // 238
|
||||
0x06, 0xBF, 0x0C, 0x07, // 239
|
||||
0x06, 0xCB, 0x0B, 0x07, // 240
|
||||
0x06, 0xD6, 0x0C, 0x07, // 241
|
||||
0x06, 0xE2, 0x0B, 0x07, // 242
|
||||
0x06, 0xED, 0x0C, 0x07, // 243
|
||||
0x06, 0xF9, 0x0B, 0x07, // 244
|
||||
0x07, 0x04, 0x0C, 0x07, // 245
|
||||
0x07, 0x10, 0x0C, 0x07, // 246
|
||||
0x07, 0x1C, 0x0C, 0x07, // 247
|
||||
0x07, 0x28, 0x0C, 0x07, // 248
|
||||
0x07, 0x34, 0x0E, 0x08, // 249
|
||||
0x07, 0x42, 0x0C, 0x07, // 250
|
||||
0x07, 0x4E, 0x0C, 0x07, // 251
|
||||
0x07, 0x5A, 0x0C, 0x07, // 252
|
||||
0x07, 0x66, 0x0C, 0x07, // 253
|
||||
0x07, 0x72, 0x0C, 0x07, // 254
|
||||
0x07, 0x7E, 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
|
||||
0x48, 0x01, 0x70, 0x01, 0xC0, 0x03, 0x70, 0x01, 0x48, 0x01, // 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
|
||||
0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x78, // 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
|
||||
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 175
|
||||
0x00, 0x00, 0x38, 0x00, 0x28, 0x00, 0x38, // 176
|
||||
0x40, 0x02, 0x40, 0x02, 0xF0, 0x03, 0x40, 0x02, 0x40, 0x02, // 177
|
||||
0x48, 0x00, 0x68, 0x00, 0x58, // 178
|
||||
0x48, 0x00, 0x58, 0x00, 0x68, // 179
|
||||
0x00, 0x00, 0x10, 0x00, 0x08, // 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
|
||||
0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 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, 0x06, 0x00, 0x09, 0xA0, 0x09, 0x00, 0x04, // 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/OLEDDisplayFontsRU.h
Normal file
11
src/graphics/fonts/OLEDDisplayFontsRU.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef OLEDDISPLAYFONTSRU_h
|
||||
#define OLEDDISPLAYFONTSRU_h
|
||||
|
||||
#ifdef ARDUINO
|
||||
#include <Arduino.h>
|
||||
#elif __MBED__
|
||||
#define PROGMEM
|
||||
#endif
|
||||
|
||||
extern const uint8_t ArialMT_Plain_10_RU[] PROGMEM;
|
||||
#endif
|
||||
@@ -1,9 +1,13 @@
|
||||
#pragma once
|
||||
#include "Observer.h"
|
||||
|
||||
#define ANYKEY 0xFF
|
||||
#define MATRIXKEY 0xFE
|
||||
|
||||
typedef struct _InputEvent {
|
||||
const char* source;
|
||||
char inputEvent;
|
||||
char kbchar;
|
||||
} InputEvent;
|
||||
class InputBroker :
|
||||
public Observable<const InputEvent *>
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
#include "configuration.h"
|
||||
#include "RotaryEncoderInterruptBase.h"
|
||||
#include "configuration.h"
|
||||
|
||||
RotaryEncoderInterruptBase::RotaryEncoderInterruptBase(
|
||||
const char *name) :
|
||||
concurrency::OSThread(name)
|
||||
RotaryEncoderInterruptBase::RotaryEncoderInterruptBase(const char *name) : concurrency::OSThread(name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptBase::init(
|
||||
uint8_t pinA, uint8_t pinB, uint8_t pinPress,
|
||||
char eventCw, char eventCcw, char eventPressed,
|
||||
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress) :
|
||||
uint8_t pinA, uint8_t pinB, uint8_t pinPress, char eventCw, char eventCcw, char eventPressed,
|
||||
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress) :
|
||||
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)())
|
||||
{
|
||||
this->_pinA = pinA;
|
||||
@@ -24,42 +21,34 @@ void RotaryEncoderInterruptBase::init(
|
||||
pinMode(this->_pinA, INPUT_PULLUP);
|
||||
pinMode(this->_pinB, INPUT_PULLUP);
|
||||
|
||||
// attachInterrupt(pinPress, onIntPress, RISING);
|
||||
// attachInterrupt(pinPress, onIntPress, RISING);
|
||||
attachInterrupt(pinPress, onIntPress, RISING);
|
||||
attachInterrupt(this->_pinA, onIntA, CHANGE);
|
||||
attachInterrupt(this->_pinB, onIntB, CHANGE);
|
||||
|
||||
this->rotaryLevelA = digitalRead(this->_pinA);
|
||||
this->rotaryLevelB = digitalRead(this->_pinB);
|
||||
DEBUG_MSG("Rotary initialized (%d, %d, %d)\n",
|
||||
this->_pinA, this->_pinB, pinPress);
|
||||
DEBUG_MSG("Rotary initialized (%d, %d, %d)\n", this->_pinA, this->_pinB, pinPress);
|
||||
}
|
||||
|
||||
|
||||
int32_t RotaryEncoderInterruptBase::runOnce()
|
||||
{
|
||||
InputEvent e;
|
||||
e.inputEvent = InputEventChar_KEY_NONE;
|
||||
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
e.source = this->_originName;
|
||||
|
||||
if (this->action == ROTARY_ACTION_PRESSED)
|
||||
{
|
||||
if (this->action == ROTARY_ACTION_PRESSED) {
|
||||
DEBUG_MSG("Rotary event Press\n");
|
||||
e.inputEvent = this->_eventPressed;
|
||||
}
|
||||
else if (this->action == ROTARY_ACTION_CW)
|
||||
{
|
||||
} else if (this->action == ROTARY_ACTION_CW) {
|
||||
DEBUG_MSG("Rotary event CW\n");
|
||||
e.inputEvent = this->_eventCw;
|
||||
}
|
||||
else if (this->action == ROTARY_ACTION_CCW)
|
||||
{
|
||||
} else if (this->action == ROTARY_ACTION_CCW) {
|
||||
DEBUG_MSG("Rotary event CCW\n");
|
||||
e.inputEvent = this->_eventCcw;
|
||||
}
|
||||
|
||||
if (e.inputEvent != InputEventChar_KEY_NONE)
|
||||
{
|
||||
if (e.inputEvent != ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
@@ -68,7 +57,6 @@ int32_t RotaryEncoderInterruptBase::runOnce()
|
||||
return 30000; // TODO: technically this can be MAX_INT
|
||||
}
|
||||
|
||||
|
||||
void RotaryEncoderInterruptBase::intPressHandler()
|
||||
{
|
||||
this->action = ROTARY_ACTION_PRESSED;
|
||||
@@ -79,66 +67,47 @@ void RotaryEncoderInterruptBase::intAHandler()
|
||||
{
|
||||
// CW rotation (at least on most common rotary encoders)
|
||||
int currentLevelA = digitalRead(this->_pinA);
|
||||
if (this->rotaryLevelA == currentLevelA)
|
||||
{
|
||||
if (this->rotaryLevelA == currentLevelA) {
|
||||
return;
|
||||
}
|
||||
this->rotaryLevelA = currentLevelA;
|
||||
this->rotaryStateCCW = intHandler(
|
||||
currentLevelA == HIGH,
|
||||
this->rotaryLevelB,
|
||||
ROTARY_ACTION_CCW,
|
||||
this->rotaryStateCCW);
|
||||
this->rotaryStateCCW = intHandler(currentLevelA == HIGH, this->rotaryLevelB, ROTARY_ACTION_CCW, this->rotaryStateCCW);
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptBase::intBHandler()
|
||||
{
|
||||
// CW rotation (at least on most common rotary encoders)
|
||||
int currentLevelB = digitalRead(this->_pinB);
|
||||
if (this->rotaryLevelB == currentLevelB)
|
||||
{
|
||||
if (this->rotaryLevelB == currentLevelB) {
|
||||
return;
|
||||
}
|
||||
this->rotaryLevelB = currentLevelB;
|
||||
this->rotaryStateCW = intHandler(
|
||||
currentLevelB == HIGH,
|
||||
this->rotaryLevelA,
|
||||
ROTARY_ACTION_CW,
|
||||
this->rotaryStateCW);
|
||||
this->rotaryStateCW = intHandler(currentLevelB == HIGH, this->rotaryLevelA, ROTARY_ACTION_CW, this->rotaryStateCW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rotary action implementation.
|
||||
* We assume, the following pin setup:
|
||||
* A --||
|
||||
* GND --||]========
|
||||
* GND --||]========
|
||||
* B --||
|
||||
*
|
||||
*
|
||||
* @return The new state for rotary pin.
|
||||
*/
|
||||
RotaryEncoderInterruptBaseStateType RotaryEncoderInterruptBase::intHandler(
|
||||
bool actualPinRaising,
|
||||
int otherPinLevel,
|
||||
RotaryEncoderInterruptBaseActionType action,
|
||||
RotaryEncoderInterruptBaseStateType state)
|
||||
RotaryEncoderInterruptBaseStateType RotaryEncoderInterruptBase::intHandler(bool actualPinRaising, int otherPinLevel,
|
||||
RotaryEncoderInterruptBaseActionType action,
|
||||
RotaryEncoderInterruptBaseStateType state)
|
||||
{
|
||||
RotaryEncoderInterruptBaseStateType newState =
|
||||
state;
|
||||
if (actualPinRaising && (otherPinLevel == LOW))
|
||||
{
|
||||
if (state == ROTARY_EVENT_CLEARED)
|
||||
{
|
||||
RotaryEncoderInterruptBaseStateType newState = state;
|
||||
if (actualPinRaising && (otherPinLevel == LOW)) {
|
||||
if (state == ROTARY_EVENT_CLEARED) {
|
||||
newState = ROTARY_EVENT_OCCURRED;
|
||||
if ((this->action != ROTARY_ACTION_PRESSED)
|
||||
&& (this->action != action))
|
||||
{
|
||||
if ((this->action != ROTARY_ACTION_PRESSED) && (this->action != action)) {
|
||||
this->action = action;
|
||||
DEBUG_MSG("Rotary action\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!actualPinRaising && (otherPinLevel == HIGH))
|
||||
{
|
||||
} else if (!actualPinRaising && (otherPinLevel == HIGH)) {
|
||||
// Logic to prevent bouncing.
|
||||
newState = ROTARY_EVENT_CLEARED;
|
||||
}
|
||||
|
||||
@@ -1,45 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "SinglePortModule.h" // TODO: what header file to include?
|
||||
#include "InputBroker.h"
|
||||
#include "SinglePortModule.h" // TODO: what header file to include?
|
||||
|
||||
enum RotaryEncoderInterruptBaseStateType
|
||||
{
|
||||
ROTARY_EVENT_OCCURRED,
|
||||
ROTARY_EVENT_CLEARED
|
||||
};
|
||||
enum RotaryEncoderInterruptBaseStateType { ROTARY_EVENT_OCCURRED, ROTARY_EVENT_CLEARED };
|
||||
|
||||
enum RotaryEncoderInterruptBaseActionType
|
||||
{
|
||||
ROTARY_ACTION_NONE,
|
||||
ROTARY_ACTION_PRESSED,
|
||||
ROTARY_ACTION_CW,
|
||||
ROTARY_ACTION_CCW
|
||||
};
|
||||
enum RotaryEncoderInterruptBaseActionType { ROTARY_ACTION_NONE, ROTARY_ACTION_PRESSED, ROTARY_ACTION_CW, ROTARY_ACTION_CCW };
|
||||
|
||||
class RotaryEncoderInterruptBase :
|
||||
public Observable<const InputEvent *>,
|
||||
private concurrency::OSThread
|
||||
class RotaryEncoderInterruptBase : public Observable<const InputEvent *>, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit RotaryEncoderInterruptBase(
|
||||
const char *name);
|
||||
void init(
|
||||
uint8_t pinA, uint8_t pinB, uint8_t pinPress,
|
||||
char eventCw, char eventCcw, char eventPressed,
|
||||
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress);
|
||||
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)());
|
||||
explicit RotaryEncoderInterruptBase(const char *name);
|
||||
void init(uint8_t pinA, uint8_t pinB, uint8_t pinPress, char eventCw, char eventCcw, char eventPressed,
|
||||
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress);
|
||||
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)());
|
||||
void intPressHandler();
|
||||
void intAHandler();
|
||||
void intBHandler();
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
RotaryEncoderInterruptBaseStateType intHandler(
|
||||
bool actualPinRaising,
|
||||
int otherPinLevel,
|
||||
RotaryEncoderInterruptBaseActionType action,
|
||||
RotaryEncoderInterruptBaseStateType state);
|
||||
RotaryEncoderInterruptBaseStateType intHandler(bool actualPinRaising, int otherPinLevel,
|
||||
RotaryEncoderInterruptBaseActionType action,
|
||||
RotaryEncoderInterruptBaseStateType state);
|
||||
|
||||
volatile RotaryEncoderInterruptBaseStateType rotaryStateCW = ROTARY_EVENT_CLEARED;
|
||||
volatile RotaryEncoderInterruptBaseStateType rotaryStateCCW = ROTARY_EVENT_CLEARED;
|
||||
@@ -50,8 +33,8 @@ class RotaryEncoderInterruptBase :
|
||||
private:
|
||||
uint8_t _pinA = 0;
|
||||
uint8_t _pinB = 0;
|
||||
char _eventCw = InputEventChar_KEY_NONE;
|
||||
char _eventCcw = InputEventChar_KEY_NONE;
|
||||
char _eventPressed = InputEventChar_KEY_NONE;
|
||||
char _eventCw = ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventCcw = ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventPressed = ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
const char *_originName;
|
||||
};
|
||||
|
||||
@@ -3,37 +3,26 @@
|
||||
|
||||
RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
|
||||
|
||||
RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() :
|
||||
RotaryEncoderInterruptBase(
|
||||
"rotEnc1")
|
||||
{
|
||||
}
|
||||
RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() : RotaryEncoderInterruptBase("rotEnc1") {}
|
||||
|
||||
void RotaryEncoderInterruptImpl1::init()
|
||||
{
|
||||
if (!radioConfig.preferences.rotary1_enabled)
|
||||
{
|
||||
if (!moduleConfig.canned_message.rotary1_enabled) {
|
||||
// Input device is disabled.
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t pinA = radioConfig.preferences.inputbroker_pin_a;
|
||||
uint8_t pinB = radioConfig.preferences.inputbroker_pin_b;
|
||||
uint8_t pinPress = radioConfig.preferences.inputbroker_pin_press;
|
||||
char eventCw =
|
||||
static_cast<char>(radioConfig.preferences.inputbroker_event_cw);
|
||||
char eventCcw =
|
||||
static_cast<char>(radioConfig.preferences.inputbroker_event_ccw);
|
||||
char eventPressed =
|
||||
static_cast<char>(radioConfig.preferences.inputbroker_event_press);
|
||||
uint8_t pinA = moduleConfig.canned_message.inputbroker_pin_a;
|
||||
uint8_t pinB = moduleConfig.canned_message.inputbroker_pin_b;
|
||||
uint8_t pinPress = moduleConfig.canned_message.inputbroker_pin_press;
|
||||
char eventCw = static_cast<char>(moduleConfig.canned_message.inputbroker_event_cw);
|
||||
char eventCcw = static_cast<char>(moduleConfig.canned_message.inputbroker_event_ccw);
|
||||
char eventPressed = static_cast<char>(moduleConfig.canned_message.inputbroker_event_press);
|
||||
|
||||
//radioConfig.preferences.ext_notification_module_output
|
||||
RotaryEncoderInterruptBase::init(
|
||||
pinA, pinB, pinPress,
|
||||
eventCw, eventCcw, eventPressed,
|
||||
RotaryEncoderInterruptImpl1::handleIntA,
|
||||
RotaryEncoderInterruptImpl1::handleIntB,
|
||||
RotaryEncoderInterruptImpl1::handleIntPressed);
|
||||
// moduleConfig.canned_message.ext_notification_module_output
|
||||
RotaryEncoderInterruptBase::init(pinA, pinB, pinPress, eventCw, eventCcw, eventPressed,
|
||||
RotaryEncoderInterruptImpl1::handleIntA, RotaryEncoderInterruptImpl1::handleIntB,
|
||||
RotaryEncoderInterruptImpl1::handleIntPressed);
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user